summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /compiler/rustc_middle
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle')
-rw-r--r--compiler/rustc_middle/Cargo.toml40
-rw-r--r--compiler/rustc_middle/README.md3
-rw-r--r--compiler/rustc_middle/benches/lib.rs54
-rw-r--r--compiler/rustc_middle/src/arena.rs108
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs435
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs140
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs1405
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs182
-rw-r--r--compiler/rustc_middle/src/hir/nested_filter.rs31
-rw-r--r--compiler/rustc_middle/src/hir/place.rs117
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs363
-rw-r--r--compiler/rustc_middle/src/infer/mod.rs32
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs162
-rw-r--r--compiler/rustc_middle/src/lib.rs106
-rw-r--r--compiler/rustc_middle/src/lint.rs443
-rw-r--r--compiler/rustc_middle/src/macros.rs232
-rw-r--r--compiler/rustc_middle/src/metadata.rs26
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs146
-rw-r--r--compiler/rustc_middle/src/middle/dependency_format.rs28
-rw-r--r--compiler/rustc_middle/src/middle/exported_symbols.rs72
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs61
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs85
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs37
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs64
-rw-r--r--compiler/rustc_middle/src/middle/region.rs443
-rw-r--r--compiler/rustc_middle/src/middle/resolve_lifetime.rs54
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs591
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs147
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs186
-rw-r--r--compiler/rustc_middle/src/mir/generic_graph.rs69
-rw-r--r--compiler/rustc_middle/src/mir/generic_graphviz.rs173
-rw-r--r--compiler/rustc_middle/src/mir/graph_cyclic_cache.rs63
-rw-r--r--compiler/rustc_middle/src/mir/graphviz.rs134
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs1300
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs551
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs633
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs307
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs217
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs651
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2900
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs527
-rw-r--r--compiler/rustc_middle/src/mir/patch.rs196
-rw-r--r--compiler/rustc_middle/src/mir/predecessors.rs78
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs1067
-rw-r--r--compiler/rustc_middle/src/mir/query.rs476
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs691
-rw-r--r--compiler/rustc_middle/src/mir/switch_sources.rs78
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs1168
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs307
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs448
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs388
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs240
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs190
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1330
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2060
-rw-r--r--compiler/rustc_middle/src/tests.rs13
-rw-r--r--compiler/rustc_middle/src/thir.rs821
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs244
-rw-r--r--compiler/rustc_middle/src/traits/chalk.rs403
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs1026
-rw-r--r--compiler/rustc_middle/src/traits/query.rs230
-rw-r--r--compiler/rustc_middle/src/traits/select.rs312
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs261
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs135
-rw-r--r--compiler/rustc_middle/src/traits/util.rs49
-rw-r--r--compiler/rustc_middle/src/ty/_match.rs124
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs194
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs198
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs569
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs195
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs22
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs73
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs454
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs527
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs326
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs483
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs239
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs104
-rw-r--r--compiler/rustc_middle/src/ty/context.rs3018
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs501
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs74
-rw-r--r--compiler/rustc_middle/src/ty/error.rs965
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs405
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs342
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs797
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs349
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs135
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs145
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs234
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs746
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs3504
-rw-r--r--compiler/rustc_middle/src/ty/list.rs215
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2518
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs283
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs119
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs327
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2789
-rw-r--r--compiler/rustc_middle/src/ty/query.rs386
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs841
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs57
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1304
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2295
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs785
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs272
-rw-r--r--compiler/rustc_middle/src/ty/util.rs1294
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs745
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs117
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs207
-rw-r--r--compiler/rustc_middle/src/util/bug.rs54
-rw-r--r--compiler/rustc_middle/src/util/common.rs67
-rw-r--r--compiler/rustc_middle/src/util/common/tests.rs14
111 files changed, 54941 insertions, 0 deletions
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
new file mode 100644
index 000000000..008d2c709
--- /dev/null
+++ b/compiler/rustc_middle/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+name = "rustc_middle"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+doctest = false
+
+[dependencies]
+rustc_arena = { path = "../rustc_arena" }
+bitflags = "1.2.1"
+either = "1.5.0"
+gsgdt = "0.1.2"
+tracing = "0.1"
+rustc-rayon = { version = "0.4.0", optional = true }
+rustc-rayon-core = { version = "0.4.0", optional = true }
+polonius-engine = "0.13.0"
+rustc_apfloat = { path = "../rustc_apfloat" }
+rustc_attr = { path = "../rustc_attr" }
+rustc_feature = { path = "../rustc_feature" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_target = { path = "../rustc_target" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_query_system = { path = "../rustc_query_system" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_index = { path = "../rustc_index" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_ast = { path = "../rustc_ast" }
+rustc_span = { path = "../rustc_span" }
+chalk-ir = "0.80.0"
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+rustc_session = { path = "../rustc_session" }
+rustc_type_ir = { path = "../rustc_type_ir" }
+rand = "0.8.4"
+rand_xoshiro = "0.6.0"
+
+[features]
+rustc_use_parallel_compiler = ["rustc-rayon", "rustc-rayon-core"]
diff --git a/compiler/rustc_middle/README.md b/compiler/rustc_middle/README.md
new file mode 100644
index 000000000..de58f546c
--- /dev/null
+++ b/compiler/rustc_middle/README.md
@@ -0,0 +1,3 @@
+For more information about how rustc works, see the [rustc dev guide].
+
+[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/
diff --git a/compiler/rustc_middle/benches/lib.rs b/compiler/rustc_middle/benches/lib.rs
new file mode 100644
index 000000000..237751bcb
--- /dev/null
+++ b/compiler/rustc_middle/benches/lib.rs
@@ -0,0 +1,54 @@
+#![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/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
new file mode 100644
index 000000000..b94de537d
--- /dev/null
+++ b/compiler/rustc_middle/src/arena.rs
@@ -0,0 +1,108 @@
+/// This higher-order macro declares a list of types which can be allocated by `Arena`.
+///
+/// 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) => (
+ $macro!([
+ [] layout: rustc_target::abi::LayoutS<'tcx>,
+ [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
+ // AdtDef are interned and compared by address
+ [decode] adt_def: rustc_middle::ty::AdtDefData,
+ [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<'tcx>>,
+ [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<'tcx>>,
+ [decode] mir: rustc_middle::mir::Body<'tcx>,
+ [] steal_promoted:
+ rustc_data_structures::steal::Steal<
+ rustc_index::vec::IndexVec<
+ rustc_middle::mir::Promoted,
+ rustc_middle::mir::Body<'tcx>
+ >
+ >,
+ [decode] promoted:
+ rustc_index::vec::IndexVec<
+ rustc_middle::mir::Promoted,
+ rustc_middle::mir::Body<'tcx>
+ >,
+ [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
+ [decode] borrowck_result:
+ rustc_middle::mir::BorrowCheckResult<'tcx>,
+ [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
+ [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
+ [] const_allocs: rustc_middle::mir::interpret::Allocation,
+ [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
+ // Required for the incremental on-disk cache
+ [] mir_keys: rustc_hir::def_id::DefIdSet,
+ [] dropck_outlives:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx,
+ rustc_middle::traits::query::DropckOutlivesResult<'tcx>
+ >
+ >,
+ [] normalize_projection_ty:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx,
+ rustc_middle::traits::query::NormalizationResult<'tcx>
+ >
+ >,
+ [] implied_outlives_bounds:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx,
+ Vec<rustc_middle::traits::query::OutlivesBound<'tcx>>
+ >
+ >,
+ [] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>,
+ [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>,
+ [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>,
+ [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>,
+ [] type_op_subtype:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx, ()>
+ >,
+ [] type_op_normalize_poly_fn_sig:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::PolyFnSig<'tcx>>
+ >,
+ [] type_op_normalize_fn_sig:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>>
+ >,
+ [] type_op_normalize_predicate:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>>
+ >,
+ [] type_op_normalize_ty:
+ rustc_middle::infer::canonical::Canonical<'tcx,
+ rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
+ >,
+ [] all_traits: Vec<rustc_hir::def_id::DefId>,
+ [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
+ [] foreign_module: rustc_session::cstore::ForeignModule,
+ [] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
+ [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
+ [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
+ [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
+ [decode] attribute: rustc_ast::Attribute,
+ [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
+ [] hir_id_set: rustc_hir::HirIdSet,
+
+ // Interned types
+ [] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>,
+ [] predicates: rustc_middle::ty::PredicateS<'tcx>,
+ [] consts: rustc_middle::ty::ConstS<'tcx>,
+
+ // Note that this deliberately duplicates items in the `rustc_hir::arena`,
+ // since we need to allocate this type on both the `rustc_hir` arena
+ // (during lowering) and the `librustc_middle` arena (for decoding MIR)
+ [decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
+ [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+ [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
+ [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
+
+ [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
+ ]);
+ )
+}
+
+arena_types!(rustc_arena::declare_arena);
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
new file mode 100644
index 000000000..2d095438f
--- /dev/null
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -0,0 +1,435 @@
+//! Nodes in the dependency graph.
+//!
+//! A node in the [dependency graph] is represented by a [`DepNode`].
+//! 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. The fingerprinting approach 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. Each `DepKind` has its own parameters that are
+//! needed at runtime in order to construct a valid `DepNode` fingerprint.
+//! However, only `CompileCodegenUnit` and `CompileMonoItem` are constructed
+//! explicitly (with `make_compile_codegen_unit` cq `make_compile_mono_item`).
+//!
+//! 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 could 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.
+//!
+//! `make_compile_codegen_unit` and `make_compile_mono_items`, 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.
+//!
+//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
+
+use crate::mir::mono::MonoItem;
+use crate::ty::TyCtxt;
+
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
+use rustc_hir::definitions::DefPathHash;
+use rustc_hir::HirId;
+use rustc_query_system::dep_graph::FingerprintStyle;
+use rustc_span::symbol::Symbol;
+use std::hash::Hash;
+
+pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
+
+/// This struct stores metadata about each DepKind.
+///
+/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
+/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
+/// jump table instead of large matches.
+pub struct DepKindStruct {
+ /// Anonymous queries cannot be replayed from one compiler invocation to the next.
+ /// When their result is needed, it is recomputed. They are useful for fine-grained
+ /// dependency tracking, and caching within one compiler invocation.
+ pub is_anon: bool,
+
+ /// Eval-always queries do not track their dependencies, and are always recomputed, even if
+ /// their inputs have not changed since the last compiler invocation. The result is still
+ /// cached within one compiler invocation.
+ pub is_eval_always: bool,
+
+ /// Whether the query key can be recovered from the hashed fingerprint.
+ /// See [DepNodeParams] trait for the behaviour of each key type.
+ pub fingerprint_style: FingerprintStyle,
+
+ /// 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_promoted` 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`.
+ pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>,
+
+ /// Invoke a query to put the on-disk cached value in memory.
+ pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>,
+}
+
+impl DepKind {
+ #[inline(always)]
+ pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
+ // Only fetch the DepKindStruct once.
+ let data = tcx.query_kind(self);
+ if data.is_anon {
+ return FingerprintStyle::Opaque;
+ }
+ data.fingerprint_style
+ }
+}
+
+macro_rules! define_dep_nodes {
+ (<$tcx:tt>
+ $(
+ [$($attrs:tt)*]
+ $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
+ ,)*
+ ) => (
+ #[macro_export]
+ macro_rules! make_dep_kind_array {
+ ($mod:ident) => {[ $($mod::$variant()),* ]};
+ }
+
+ /// This enum serves as an index into arrays built by `make_dep_kind_array`.
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+ #[allow(non_camel_case_types)]
+ pub enum DepKind {
+ $($variant),*
+ }
+
+ fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
+ match label {
+ $(stringify!($variant) => Ok(DepKind::$variant),)*
+ _ => Err(()),
+ }
+ }
+
+ /// 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);
+ )*
+ }
+ );
+}
+
+rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
+ // We use this for most things when incr. comp. is turned off.
+ [] Null,
+
+ // We use this to create a forever-red node.
+ [] Red,
+
+ [anon] TraitSelect,
+
+ // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below.
+ [] CompileCodegenUnit(Symbol),
+
+ // WARNING: if `MonoItem` is changed, make sure you update `make_compile_mono_item` below.
+ // Only used by rustc_codegen_cranelift
+ [] CompileMonoItem(MonoItem),
+]);
+
+// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
+// Be very careful changing this type signature!
+pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
+ DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
+}
+
+// WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
+// Be very careful changing this type signature!
+pub(crate) fn make_compile_mono_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ mono_item: &MonoItem<'tcx>,
+) -> DepNode {
+ DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item)
+}
+
+pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
+
+// We keep a lot of `DepNode`s in memory during compilation. It's not
+// required that their size stay the same, but we don't want to change
+// it inadvertently. This assert just ensures we're aware of any change.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static_assert_size!(DepNode, 18);
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+static_assert_size!(DepNode, 24);
+
+pub trait DepNodeExt: Sized {
+ /// Construct a DepNode from the given DepKind and DefPathHash. This
+ /// method will assert that the given DepKind actually requires a
+ /// single DefId/DefPathHash parameter.
+ fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
+
+ /// 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.
+ fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
+
+ /// Used in testing
+ fn from_label_string(
+ tcx: TyCtxt<'_>,
+ label: &str,
+ def_path_hash: DefPathHash,
+ ) -> Result<Self, ()>;
+
+ /// Used in testing
+ fn has_label_string(label: &str) -> bool;
+}
+
+impl DepNodeExt for 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.
+ fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
+ debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
+ DepNode { kind, hash: def_path_hash.0.into() }
+ }
+
+ /// 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.
+ fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
+ if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
+ Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
+ panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
+ }))
+ } else {
+ None
+ }
+ }
+
+ /// Used in testing
+ fn from_label_string(
+ tcx: TyCtxt<'_>,
+ label: &str,
+ def_path_hash: DefPathHash,
+ ) -> Result<DepNode, ()> {
+ let kind = dep_kind_from_label_string(label)?;
+
+ match kind.fingerprint_style(tcx) {
+ FingerprintStyle::Opaque => Err(()),
+ FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
+ FingerprintStyle::DefPathHash => {
+ Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
+ }
+ }
+ }
+
+ /// Used in testing
+ fn has_label_string(label: &str) -> bool {
+ dep_kind_from_label_string(label).is_ok()
+ }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::Unit
+ }
+
+ #[inline(always)]
+ fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
+ Fingerprint::ZERO
+ }
+
+ #[inline(always)]
+ fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
+ Some(())
+ }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::DefPathHash
+ }
+
+ #[inline(always)]
+ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+ tcx.def_path_hash(*self).0
+ }
+
+ #[inline(always)]
+ fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+ tcx.def_path_str(*self)
+ }
+
+ #[inline(always)]
+ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+ dep_node.extract_def_id(tcx)
+ }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::DefPathHash
+ }
+
+ #[inline(always)]
+ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+ self.to_def_id().to_fingerprint(tcx)
+ }
+
+ #[inline(always)]
+ fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+ self.to_def_id().to_debug_str(tcx)
+ }
+
+ #[inline(always)]
+ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+ dep_node.extract_def_id(tcx).map(|id| id.expect_local())
+ }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::DefPathHash
+ }
+
+ #[inline(always)]
+ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+ let def_id = self.as_def_id();
+ def_id.to_fingerprint(tcx)
+ }
+
+ #[inline(always)]
+ fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+ tcx.crate_name(*self).to_string()
+ }
+
+ #[inline(always)]
+ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+ dep_node.extract_def_id(tcx).map(|id| id.krate)
+ }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::Opaque
+ }
+
+ // 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.
+ #[inline(always)]
+ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> 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)
+ }
+
+ #[inline(always)]
+ 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<TyCtxt<'tcx>> for HirId {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::Opaque
+ }
+
+ // 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.
+ #[inline(always)]
+ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+ let HirId { owner, local_id } = *self;
+
+ let def_path_hash = tcx.def_path_hash(owner.to_def_id());
+ let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());
+
+ def_path_hash.0.combine(local_id)
+ }
+}
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
new file mode 100644
index 000000000..c8b3b52b0
--- /dev/null
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -0,0 +1,140 @@
+use crate::ty::{self, TyCtxt};
+use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_session::Session;
+
+#[macro_use]
+mod dep_node;
+
+pub use rustc_query_system::dep_graph::{
+ debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex,
+ SerializedDepNodeIndex, WorkProduct, WorkProductId,
+};
+
+pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
+pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
+
+pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
+pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
+pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
+pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
+pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
+pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
+
+impl rustc_query_system::dep_graph::DepKind for DepKind {
+ const NULL: Self = DepKind::Null;
+ const RED: Self = DepKind::Red;
+
+ fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{:?}(", node.kind)?;
+
+ ty::tls::with_opt(|opt_tcx| {
+ if let Some(tcx) = opt_tcx {
+ if let Some(def_id) = node.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(*node) {
+ write!(f, "{}", s)?;
+ } else {
+ write!(f, "{}", node.hash)?;
+ }
+ } else {
+ write!(f, "{}", node.hash)?;
+ }
+ Ok(())
+ })?;
+
+ write!(f, ")")
+ }
+
+ fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
+ where
+ OP: FnOnce() -> R,
+ {
+ ty::tls::with_context(|icx| {
+ let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() };
+
+ ty::tls::enter_context(&icx, |_| op())
+ })
+ }
+
+ fn read_deps<OP>(op: OP)
+ where
+ OP: for<'a> FnOnce(TaskDepsRef<'a>),
+ {
+ ty::tls::with_context_opt(|icx| {
+ let Some(icx) = icx else { return };
+ op(icx.task_deps)
+ })
+ }
+}
+
+impl<'tcx> DepContext for TyCtxt<'tcx> {
+ type DepKind = DepKind;
+
+ #[inline]
+ fn with_stable_hashing_context<R>(&self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R {
+ TyCtxt::with_stable_hashing_context(*self, f)
+ }
+
+ #[inline]
+ fn dep_graph(&self) -> &DepGraph {
+ &self.dep_graph
+ }
+
+ #[inline(always)]
+ fn profiler(&self) -> &SelfProfilerRef {
+ &self.prof
+ }
+
+ #[inline(always)]
+ fn sess(&self) -> &Session {
+ self.sess
+ }
+
+ #[inline(always)]
+ fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
+ kind.fingerprint_style(*self)
+ }
+
+ #[inline(always)]
+ fn is_eval_always(&self, kind: DepKind) -> bool {
+ self.query_kind(kind).is_eval_always
+ }
+
+ fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
+ debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+ // 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"
+ );
+
+ let cb = self.query_kind(dep_node.kind);
+ if let Some(f) = cb.force_from_dep_node {
+ f(*self, dep_node);
+ true
+ } else {
+ false
+ }
+ }
+
+ fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
+ let cb = self.query_kind(dep_node.kind);
+ if let Some(f) = cb.try_load_from_on_disk_cache {
+ f(*self, dep_node)
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
new file mode 100644
index 000000000..47b04c33e
--- /dev/null
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -0,0 +1,1405 @@
+use crate::hir::{ModuleItems, Owner};
+use crate::ty::{DefIdTree, TyCtxt};
+use rustc_ast as ast;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::*;
+use rustc_index::vec::Idx;
+use rustc_middle::hir::nested_filter;
+use rustc_span::def_id::StableCrateId;
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
+
+fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
+ match node {
+ Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
+ | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
+ Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. })
+ | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
+ Some(fn_decl)
+ }
+ _ => None,
+ }
+}
+
+pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> {
+ match &node {
+ Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
+ | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(sig),
+ _ => None,
+ }
+}
+
+#[inline]
+pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
+ match node {
+ Node::Item(Item {
+ kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
+ ..
+ })
+ | Node::TraitItem(TraitItem {
+ kind:
+ TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)),
+ ..
+ })
+ | Node::ImplItem(ImplItem {
+ kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
+ ..
+ })
+ | Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body),
+
+ Node::AnonConst(constant) => Some(constant.body),
+
+ _ => None,
+ }
+}
+
+fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool {
+ match associated_body(node) {
+ Some(b) => b.hir_id == hir_id,
+ None => false,
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct Map<'hir> {
+ pub(super) tcx: TyCtxt<'hir>,
+}
+
+/// An iterator that walks up the ancestor tree of a given `HirId`.
+/// Constructed using `tcx.hir().parent_iter(hir_id)`.
+pub struct ParentHirIterator<'hir> {
+ current_id: HirId,
+ map: Map<'hir>,
+}
+
+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(node) = self.map.find(parent_id) {
+ return Some((parent_id, node));
+ }
+ // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+ }
+ }
+}
+
+/// An iterator that walks up the ancestor tree of a given `HirId`.
+/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
+pub struct ParentOwnerIterator<'hir> {
+ current_id: HirId,
+ map: Map<'hir>,
+}
+
+impl<'hir> Iterator for ParentOwnerIterator<'hir> {
+ type Item = (LocalDefId, OwnerNode<'hir>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.current_id.local_id.index() != 0 {
+ self.current_id.local_id = ItemLocalId::new(0);
+ if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
+ return Some((self.current_id.owner, node.node));
+ }
+ }
+ 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.def_key(self.current_id.owner).parent;
+
+ let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| {
+ let def_id = LocalDefId { local_def_index };
+ self.map.local_def_id_to_hir_id(def_id).owner
+ });
+ self.current_id = HirId::make_owner(parent_id);
+
+ // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+ if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
+ return Some((self.current_id.owner, node.node));
+ }
+ }
+ }
+}
+
+impl<'hir> Map<'hir> {
+ pub fn krate(self) -> &'hir Crate<'hir> {
+ self.tcx.hir_crate(())
+ }
+
+ pub fn root_module(self) -> &'hir Mod<'hir> {
+ match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) {
+ Some(OwnerNode::Crate(item)) => item,
+ _ => bug!(),
+ }
+ }
+
+ pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
+ self.tcx.hir_crate_items(()).items.iter().copied()
+ }
+
+ pub fn module_items(self, module: LocalDefId) -> impl Iterator<Item = ItemId> + 'hir {
+ self.tcx.hir_module_items(module).items()
+ }
+
+ pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) {
+ par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id));
+ }
+
+ pub fn def_key(self, def_id: LocalDefId) -> DefKey {
+ // Accessing the DefKey is ok, since it is part of DefPathHash.
+ self.tcx.definitions_untracked().def_key(def_id)
+ }
+
+ 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: LocalDefId) -> DefPath {
+ // Accessing the DefPath is ok, since it is part of DefPathHash.
+ self.tcx.definitions_untracked().def_path(def_id)
+ }
+
+ #[inline]
+ pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
+ // Accessing the DefPathHash is ok, it is incr. comp. stable.
+ self.tcx.definitions_untracked().def_path_hash(def_id)
+ }
+
+ #[inline]
+ pub fn local_def_id(self, hir_id: HirId) -> LocalDefId {
+ 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(hir_id)
+ )
+ })
+ }
+
+ #[inline]
+ pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> {
+ if hir_id.local_id == ItemLocalId::new(0) {
+ Some(hir_id.owner)
+ } else {
+ self.tcx
+ .hir_owner_nodes(hir_id.owner)
+ .as_owner()?
+ .local_id_to_def_id
+ .get(&hir_id.local_id)
+ .copied()
+ }
+ }
+
+ #[inline]
+ pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId {
+ self.tcx.local_def_id_to_hir_id(def_id)
+ }
+
+ /// Do not call this function directly. The query should be called.
+ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
+ let hir_id = self.local_def_id_to_hir_id(local_def_id);
+ let def_kind = match self.find(hir_id)? {
+ Node::Item(item) => match item.kind {
+ ItemKind::Static(_, mt, _) => DefKind::Static(mt),
+ ItemKind::Const(..) => DefKind::Const,
+ ItemKind::Fn(..) => DefKind::Fn,
+ ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
+ 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(_) => DefKind::ExternCrate,
+ ItemKind::Use(..) => DefKind::Use,
+ ItemKind::ForeignMod { .. } => DefKind::ForeignMod,
+ ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
+ ItemKind::Impl { .. } => DefKind::Impl,
+ },
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Fn(..) => DefKind::Fn,
+ ForeignItemKind::Static(_, mt) => DefKind::Static(mt),
+ ForeignItemKind::Type => DefKind::ForeignTy,
+ },
+ Node::TraitItem(item) => match item.kind {
+ TraitItemKind::Const(..) => DefKind::AssocConst,
+ TraitItemKind::Fn(..) => DefKind::AssocFn,
+ TraitItemKind::Type(..) => DefKind::AssocTy,
+ },
+ Node::ImplItem(item) => match item.kind {
+ ImplItemKind::Const(..) => DefKind::AssocConst,
+ ImplItemKind::Fn(..) => DefKind::AssocFn,
+ ImplItemKind::TyAlias(..) => DefKind::AssocTy,
+ },
+ Node::Variant(_) => DefKind::Variant,
+ Node::Ctor(variant_data) => {
+ // FIXME(eddyb) is this even possible, if we have a `Node::Ctor`?
+ assert_ne!(variant_data.ctor_hir_id(), 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(_) => {
+ let inline = match self.find(self.get_parent_node(hir_id)) {
+ Some(Node::Expr(&Expr {
+ kind: ExprKind::ConstBlock(ref anon_const), ..
+ })) if anon_const.hir_id == hir_id => true,
+ _ => false,
+ };
+ if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+ }
+ Node::Field(_) => DefKind::Field,
+ Node::Expr(expr) => match expr.kind {
+ ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure,
+ ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator,
+ _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
+ },
+ Node::GenericParam(param) => match param.kind {
+ GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
+ GenericParamKind::Type { .. } => DefKind::TyParam,
+ GenericParamKind::Const { .. } => DefKind::ConstParam,
+ },
+ Node::Crate(_) => DefKind::Mod,
+ Node::Stmt(_)
+ | Node::PathSegment(_)
+ | Node::Ty(_)
+ | Node::TypeBinding(_)
+ | Node::Infer(_)
+ | Node::TraitRef(_)
+ | Node::Pat(_)
+ | Node::Local(_)
+ | Node::Param(_)
+ | Node::Arm(_)
+ | Node::Lifetime(_)
+ | Node::Block(_) => return None,
+ };
+ Some(def_kind)
+ }
+
+ pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
+ if id.local_id == ItemLocalId::from_u32(0) {
+ Some(self.tcx.hir_owner_parent(id.owner))
+ } else {
+ let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
+ let node = owner.nodes[id.local_id].as_ref()?;
+ let hir_id = HirId { owner: id.owner, local_id: node.parent };
+ Some(hir_id)
+ }
+ }
+
+ pub fn get_parent_node(self, hir_id: HirId) -> HirId {
+ self.find_parent_node(hir_id)
+ .unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
+ }
+
+ /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
+ pub fn find(self, id: HirId) -> Option<Node<'hir>> {
+ if id.local_id == ItemLocalId::from_u32(0) {
+ let owner = self.tcx.hir_owner(id.owner)?;
+ Some(owner.node.into())
+ } else {
+ let owner = self.tcx.hir_owner_nodes(id.owner).as_owner()?;
+ let node = owner.nodes[id.local_id].as_ref()?;
+ Some(node.node)
+ }
+ }
+
+ /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
+ #[inline]
+ pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> {
+ self.find(self.local_def_id_to_hir_id(id))
+ }
+
+ /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
+ pub fn get(self, id: HirId) -> Node<'hir> {
+ self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
+ }
+
+ /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
+ #[inline]
+ pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> {
+ self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id))
+ }
+
+ pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
+ id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
+ }
+
+ pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
+ let node = self.tcx.hir_owner(id)?;
+ node.node.generics()
+ }
+
+ pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
+ }
+
+ pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
+ }
+
+ pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
+ }
+
+ pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
+ }
+
+ pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
+ self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
+ }
+
+ pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
+ if let Some(node) = self.find(hir_id) {
+ fn_decl(node)
+ } else {
+ bug!("no node for hir_id `{}`", hir_id)
+ }
+ }
+
+ pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
+ if let Some(node) = self.find(hir_id) {
+ fn_sig(node)
+ } else {
+ bug!("no node for hir_id `{}`", hir_id)
+ }
+ }
+
+ pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
+ for (parent, _) in self.parent_iter(hir_id) {
+ if let Some(body) = self.find(parent).map(associated_body).flatten() {
+ return self.body_owner_def_id(body);
+ }
+ }
+
+ bug!("no `enclosing_body_owner` 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.find(parent).map_or(false, |n| is_body_owner(n, hir_id)));
+ parent
+ }
+
+ pub fn body_owner_def_id(self, id: BodyId) -> LocalDefId {
+ self.local_def_id(self.body_owner(id))
+ }
+
+ /// Given a `LocalDefId`, returns the `BodyId` associated with it,
+ /// if the node is a body owner, otherwise returns `None`.
+ pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
+ self.get_if_local(id.to_def_id()).map(associated_body).flatten()
+ }
+
+ /// Given a body owner's id, returns the `BodyId` associated with it.
+ pub fn body_owned_by(self, id: LocalDefId) -> BodyId {
+ self.maybe_body_owned_by(id).unwrap_or_else(|| {
+ let hir_id = self.local_def_id_to_hir_id(id);
+ span_bug!(
+ self.span(hir_id),
+ "body_owned_by: {} has no associated body",
+ self.node_to_string(hir_id)
+ );
+ })
+ }
+
+ pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
+ self.body(id).params.iter().map(|arg| match arg.pat.kind {
+ PatKind::Binding(_, _, ident, _) => ident,
+ _ => Ident::empty(),
+ })
+ }
+
+ /// Returns the `BodyOwnerKind` of this `LocalDefId`.
+ ///
+ /// Panics if `LocalDefId` does not have an associated body.
+ pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
+ match self.tcx.def_kind(def_id) {
+ DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
+ BodyOwnerKind::Const
+ }
+ DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
+ DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
+ DefKind::Static(mt) => BodyOwnerKind::Static(mt),
+ dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
+ }
+ }
+
+ /// Returns the `ConstContext` of the body associated with this `LocalDefId`.
+ ///
+ /// Panics if `LocalDefId` does not have an associated body.
+ ///
+ /// This should only be used for determining the context of a body, a return
+ /// value of `Some` does not always suggest that the owner of the body is `const`,
+ /// just that it has to be checked as if it were.
+ pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
+ let ccx = match self.body_owner_kind(def_id) {
+ BodyOwnerKind::Const => ConstContext::Const,
+ BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
+
+ BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
+ BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
+ ConstContext::ConstFn
+ }
+ BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {
+ ConstContext::ConstFn
+ }
+ BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
+ };
+
+ Some(ccx)
+ }
+
+ /// 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 = LocalDefId> + 'hir {
+ self.tcx.hir_crate_items(()).body_owners.iter().copied()
+ }
+
+ pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
+ par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id));
+ }
+
+ pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
+ let def_kind = self.tcx.def_kind(def_id);
+ match def_kind {
+ DefKind::Trait | DefKind::TraitAlias => def_id,
+ DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id),
+ _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
+ }
+ }
+
+ pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol {
+ let def_kind = self.tcx.def_kind(def_id);
+ match def_kind {
+ DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
+ DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()),
+ _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
+ }
+ }
+
+ pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] {
+ self.tcx.all_local_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] {
+ self.attrs(CRATE_HIR_ID)
+ }
+
+ pub fn rustc_coherence_is_core(self) -> bool {
+ self.krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
+ }
+
+ pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
+ let hir_id = HirId::make_owner(module);
+ match self.tcx.hir_owner(module).map(|o| o.node) {
+ Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
+ (m, span, hir_id)
+ }
+ Some(OwnerNode::Crate(item)) => (item, item.spans.inner_span, hir_id),
+ node => panic!("not a module: {:?}", node),
+ }
+ }
+
+ /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
+ pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
+ let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID);
+ visitor.visit_mod(top_mod, span, hir_id);
+ }
+
+ /// Walks the attributes in a crate.
+ pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
+ let krate = self.krate();
+ for info in krate.owners.iter() {
+ if let MaybeOwner::Owner(info) = info {
+ for attrs in info.attrs.map.values() {
+ for a in *attrs {
+ visitor.visit_attribute(a)
+ }
+ }
+ }
+ }
+ }
+
+ /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
+ /// need to process every item-like, and don't care about visiting nested items in a particular
+ /// order then this method is the best choice. If you do care about this nesting, you should
+ /// use the `tcx.hir().walk_toplevel_module`.
+ ///
+ /// Note that this function will access HIR for all the item-likes in the crate. If you only
+ /// need to access some of them, it is usually better to manually loop on the iterators
+ /// provided by `tcx.hir_crate_items(())`.
+ ///
+ /// Please see the notes in `intravisit.rs` for more information.
+ pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V)
+ where
+ V: Visitor<'hir>,
+ {
+ let krate = self.tcx.hir_crate_items(());
+
+ for id in krate.items() {
+ visitor.visit_item(self.item(id));
+ }
+
+ for id in krate.trait_items() {
+ visitor.visit_trait_item(self.trait_item(id));
+ }
+
+ for id in krate.impl_items() {
+ visitor.visit_impl_item(self.impl_item(id));
+ }
+
+ for id in krate.foreign_items() {
+ visitor.visit_foreign_item(self.foreign_item(id));
+ }
+ }
+
+ /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to
+ /// item-likes in a single module.
+ pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
+ where
+ V: Visitor<'hir>,
+ {
+ let module = self.tcx.hir_module_items(module);
+
+ for id in module.items() {
+ visitor.visit_item(self.item(id));
+ }
+
+ for id in module.trait_items() {
+ visitor.visit_trait_item(self.trait_item(id));
+ }
+
+ for id in module.impl_items() {
+ visitor.visit_impl_item(self.impl_item(id));
+ }
+
+ for id in module.foreign_items() {
+ visitor.visit_foreign_item(self.foreign_item(id));
+ }
+ }
+
+ pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) {
+ let crate_items = self.tcx.hir_crate_items(());
+ for module in crate_items.submodules.iter() {
+ f(*module)
+ }
+ }
+
+ #[cfg(not(parallel_compiler))]
+ #[inline]
+ pub fn par_for_each_module(self, f: impl Fn(LocalDefId)) {
+ self.for_each_module(f)
+ }
+
+ #[cfg(parallel_compiler)]
+ pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync) {
+ use rustc_data_structures::sync::{par_iter, ParallelIterator};
+ par_iter_submodules(self.tcx, CRATE_DEF_ID, &f);
+
+ fn par_iter_submodules<F>(tcx: TyCtxt<'_>, module: LocalDefId, f: &F)
+ where
+ F: Fn(LocalDefId) + Sync,
+ {
+ (*f)(module);
+ let items = tcx.hir_module_items(module);
+ par_iter(&items.submodules[..]).for_each(|&sm| par_iter_submodules(tcx, sm, f));
+ }
+ }
+
+ /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+ /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ pub fn parent_iter(self, current_id: HirId) -> ParentHirIterator<'hir> {
+ ParentHirIterator { current_id, map: self }
+ }
+
+ /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+ /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
+ ParentOwnerIterator { current_id, map: self }
+ }
+
+ /// Checks if the node is left-hand side of an assignment.
+ pub fn is_lhs(self, id: HirId) -> bool {
+ match self.find(self.get_parent_node(id)) {
+ Some(Node::Expr(expr)) => match expr.kind {
+ ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
+ _ => 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_inside_const_context(self, hir_id: HirId) -> bool {
+ self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
+ }
+
+ /// 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
+ /// }
+ /// }
+ /// ```
+ ///
+ /// ```compile_fail,E0308
+ /// 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 = self.parent_iter(id).peekable();
+ let mut ignore_tail = false;
+ if let Some(node) = self.find(id) {
+ if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = 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,
+ // The current node is not the tail expression of its parent.
+ Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
+ _ => {}
+ }
+ }
+ match node {
+ Node::Item(_)
+ | Node::ForeignItem(_)
+ | Node::TraitItem(_)
+ | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. })
+ | Node::ImplItem(_) => return Some(hir_id),
+ // Ignore `return`s on the first iteration
+ Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
+ | 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) -> LocalDefId {
+ if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
+ def_id
+ } else {
+ CRATE_DEF_ID
+ }
+ }
+
+ /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
+ /// module parent is in this map.
+ pub(super) fn get_module_parent_node(self, hir_id: HirId) -> LocalDefId {
+ for (def_id, node) in self.parent_owner_iter(hir_id) {
+ if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
+ return def_id;
+ }
+ }
+ CRATE_DEF_ID
+ }
+
+ /// When on an if expression, a match arm tail expression or a match arm, give back
+ /// the enclosing `if` or `match` expression.
+ ///
+ /// Used by error reporting when there's a type error in an if or match arm caused by the
+ /// expression needing to be unit.
+ pub fn get_if_cause(self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
+ for (_, node) in self.parent_iter(hir_id) {
+ match node {
+ Node::Item(_)
+ | Node::ForeignItem(_)
+ | Node::TraitItem(_)
+ | Node::ImplItem(_)
+ | Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
+ Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
+ return Some(expr);
+ }
+ _ => {}
+ }
+ }
+ 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 self.parent_iter(hir_id) {
+ if let Node::Item(Item {
+ kind:
+ ItemKind::Fn(..)
+ | ItemKind::Const(..)
+ | ItemKind::Static(..)
+ | ItemKind::Mod(..)
+ | ItemKind::Enum(..)
+ | ItemKind::Struct(..)
+ | ItemKind::Union(..)
+ | ItemKind::Trait(..)
+ | ItemKind::Impl { .. },
+ ..
+ })
+ | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(..), .. })
+ | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(..), .. })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(..), .. })
+ | Node::Block(_) = node
+ {
+ 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 || !matches!(self.get(scope), Node::Block(_)) {
+ return scope;
+ }
+ }
+ }
+
+ pub fn get_foreign_abi(self, hir_id: HirId) -> Abi {
+ let parent = self.get_parent_item(hir_id);
+ if let Some(node) = self.tcx.hir_owner(parent) {
+ if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
+ {
+ return *abi;
+ }
+ }
+ bug!(
+ "expected foreign mod or inlined parent, found {}",
+ self.node_to_string(HirId::make_owner(parent))
+ )
+ }
+
+ pub fn expect_owner(self, id: LocalDefId) -> OwnerNode<'hir> {
+ self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node
+ }
+
+ pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
+ match self.tcx.hir_owner(id) {
+ Some(Owner { node: OwnerNode::Item(item), .. }) => item,
+ _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
+ }
+ }
+
+ pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
+ match self.tcx.hir_owner(id) {
+ Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
+ _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
+ }
+ }
+
+ pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
+ match self.tcx.hir_owner(id) {
+ Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
+ _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(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: LocalDefId) -> &'hir ForeignItem<'hir> {
+ match self.tcx.hir_owner(id) {
+ Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
+ _ => {
+ bug!("expected foreign item, found {}", self.node_to_string(HirId::make_owner(id)))
+ }
+ }
+ }
+
+ pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
+ match self.find(id) {
+ Some(Node::Expr(expr)) => expr,
+ _ => bug!("expected expr, found {}", self.node_to_string(id)),
+ }
+ }
+
+ #[inline]
+ fn opt_ident(self, id: HirId) -> Option<Ident> {
+ match self.get(id) {
+ Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
+ // A `Ctor` doesn't have an identifier itself, but its parent
+ // struct/variant does. Compare with `hir::Map::opt_span`.
+ Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
+ Node::Item(item) => Some(item.ident),
+ Node::Variant(variant) => Some(variant.ident),
+ _ => unreachable!(),
+ },
+ node => node.ident(),
+ }
+ }
+
+ #[inline]
+ pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> {
+ self.opt_ident(id).map(|ident| ident.span)
+ }
+
+ #[inline]
+ pub fn opt_name(self, id: HirId) -> Option<Symbol> {
+ self.opt_ident(id).map(|ident| ident.name)
+ }
+
+ pub fn name(self, id: HirId) -> Symbol {
+ self.opt_name(id).unwrap_or_else(|| 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.tcx.hir_attrs(id.owner).get(id.local_id)
+ }
+
+ /// Gets the span of the definition of the specified HIR node.
+ /// This is used by `tcx.def_span`.
+ pub fn span(self, hir_id: HirId) -> Span {
+ self.opt_span(hir_id)
+ .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id))
+ }
+
+ pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
+ fn until_within(outer: Span, end: Span) -> Span {
+ if let Some(end) = end.find_ancestor_inside(outer) {
+ outer.with_hi(end.hi())
+ } else {
+ outer
+ }
+ }
+
+ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) -> Span {
+ if ident.name != kw::Empty {
+ let mut span = until_within(item_span, ident.span);
+ if let Some(g) = generics
+ && !g.span.is_dummy()
+ && let Some(g_span) = g.span.find_ancestor_inside(item_span)
+ {
+ span = span.to(g_span);
+ }
+ span
+ } else {
+ item_span
+ }
+ }
+
+ let span = match self.find(hir_id)? {
+ // Function-like.
+ Node::Item(Item { kind: ItemKind::Fn(sig, ..), .. })
+ | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, ..), .. })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, ..), .. }) => sig.span,
+ // Constants and Statics.
+ Node::Item(Item {
+ kind:
+ ItemKind::Const(ty, ..)
+ | ItemKind::Static(ty, ..)
+ | ItemKind::Impl(Impl { self_ty: ty, .. }),
+ span: outer_span,
+ ..
+ })
+ | Node::TraitItem(TraitItem {
+ kind: TraitItemKind::Const(ty, ..),
+ span: outer_span,
+ ..
+ })
+ | Node::ImplItem(ImplItem {
+ kind: ImplItemKind::Const(ty, ..),
+ span: outer_span,
+ ..
+ })
+ | Node::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Static(ty, ..),
+ span: outer_span,
+ ..
+ }) => until_within(*outer_span, ty.span),
+ // With generics and bounds.
+ Node::Item(Item {
+ kind: ItemKind::Trait(_, _, generics, bounds, _),
+ span: outer_span,
+ ..
+ })
+ | Node::TraitItem(TraitItem {
+ kind: TraitItemKind::Type(bounds, _),
+ generics,
+ span: outer_span,
+ ..
+ }) => {
+ let end = if let Some(b) = bounds.last() { b.span() } else { generics.span };
+ until_within(*outer_span, end)
+ }
+ // Other cases.
+ Node::Item(item) => match &item.kind {
+ ItemKind::Use(path, _) => path.span,
+ _ => named_span(item.span, item.ident, item.kind.generics()),
+ },
+ Node::Variant(variant) => named_span(variant.span, variant.ident, None),
+ Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
+ _ => named_span(item.span, item.ident, None),
+ },
+ Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
+ Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
+ *fn_decl_span
+ }
+ _ => self.span_with_body(hir_id),
+ };
+ Some(span)
+ }
+
+ /// Like `hir.span()`, but includes the body of items
+ /// (instead of just the item header)
+ pub fn span_with_body(self, hir_id: HirId) -> Span {
+ match self.get(hir_id) {
+ Node::Param(param) => param.span,
+ Node::Item(item) => item.span,
+ Node::ForeignItem(foreign_item) => foreign_item.span,
+ Node::TraitItem(trait_item) => trait_item.span,
+ Node::ImplItem(impl_item) => impl_item.span,
+ Node::Variant(variant) => variant.span,
+ Node::Field(field) => field.span,
+ Node::AnonConst(constant) => self.body(constant.body).value.span,
+ Node::Expr(expr) => expr.span,
+ Node::Stmt(stmt) => stmt.span,
+ Node::PathSegment(seg) => {
+ let ident_span = seg.ident.span;
+ ident_span
+ .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
+ }
+ Node::Ty(ty) => ty.span,
+ Node::TypeBinding(tb) => tb.span,
+ Node::TraitRef(tr) => tr.path.span,
+ Node::Pat(pat) => pat.span,
+ Node::Arm(arm) => arm.span,
+ Node::Block(block) => block.span,
+ Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)),
+ Node::Lifetime(lifetime) => lifetime.span,
+ Node::GenericParam(param) => param.span,
+ Node::Infer(i) => i.span,
+ Node::Local(local) => local.span,
+ Node::Crate(item) => item.spans.inner_span,
+ }
+ }
+
+ pub fn span_if_local(self, id: DefId) -> Option<Span> {
+ if id.is_local() { Some(self.tcx.def_span(id)) } else { None }
+ }
+
+ 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()?),
+ }
+ }
+
+ /// Get a representation of this `id` for debugging purposes.
+ /// NOTE: Do NOT use this in diagnostics!
+ pub fn node_to_string(self, id: HirId) -> String {
+ hir_id_to_string(self, id)
+ }
+
+ /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
+ /// called with the HirId for the `{ ... }` anon const
+ pub fn opt_const_param_default_param_hir_id(self, anon_const: HirId) -> Option<HirId> {
+ match self.get(self.get_parent_node(anon_const)) {
+ Node::GenericParam(GenericParam {
+ hir_id: param_id,
+ kind: GenericParamKind::Const { .. },
+ ..
+ }) => Some(*param_id),
+ _ => None,
+ }
+ }
+}
+
+impl<'hir> intravisit::Map<'hir> for Map<'hir> {
+ fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
+ (*self).find(hir_id)
+ }
+
+ fn body(&self, id: BodyId) -> &'hir Body<'hir> {
+ (*self).body(id)
+ }
+
+ fn item(&self, id: ItemId) -> &'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)
+ }
+
+ fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ (*self).foreign_item(id)
+ }
+}
+
+pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
+ debug_assert_eq!(crate_num, LOCAL_CRATE);
+ let krate = tcx.hir_crate(());
+ let hir_body_hash = krate.hir_hash;
+
+ let upstream_crates = upstream_crates(tcx);
+
+ let resolutions = tcx.resolutions(());
+
+ // 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<_> = tcx
+ .sess
+ .source_map()
+ .files()
+ .iter()
+ .filter(|source_file| source_file.cnum == LOCAL_CRATE)
+ .map(|source_file| source_file.name_hash)
+ .collect();
+
+ source_file_names.sort_unstable();
+
+ let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
+ let mut stable_hasher = StableHasher::new();
+ hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
+ upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
+ source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+ if tcx.sess.opts.unstable_opts.incremental_relative_spans {
+ let definitions = tcx.definitions_untracked();
+ let mut owner_spans: Vec<_> = krate
+ .owners
+ .iter_enumerated()
+ .filter_map(|(def_id, info)| {
+ let _ = info.as_owner()?;
+ let def_path_hash = definitions.def_path_hash(def_id);
+ let span = resolutions.source_span[def_id];
+ debug_assert_eq!(span.parent(), None);
+ Some((def_path_hash, span))
+ })
+ .collect();
+ owner_spans.sort_unstable_by_key(|bn| bn.0);
+ owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
+ }
+ tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
+ tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
+ // Hash visibility information since it does not appear in HIR.
+ resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
+ resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
+ stable_hasher.finish()
+ });
+
+ Svh::new(crate_hash.to_smaller_hash())
+}
+
+fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
+ let mut upstream_crates: Vec<_> = tcx
+ .crates(())
+ .iter()
+ .map(|&cnum| {
+ let stable_crate_id = tcx.stable_crate_id(cnum);
+ let hash = tcx.crate_hash(cnum);
+ (stable_crate_id, hash)
+ })
+ .collect();
+ upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id);
+ upstream_crates
+}
+
+fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
+ let id_str = format!(" (hir_id={})", id);
+
+ 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.to_def_id())
+ } else if let Some(path) = map.def_path_from_hir_id(id) {
+ path.data.into_iter().map(|elem| elem.to_string()).collect::<Vec<_>>().join("::")
+ } else {
+ String::from("<missing path>")
+ }
+ })
+ };
+
+ let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default();
+ let node_str = |prefix| format!("{} {}{}", prefix, span_str(), id_str);
+
+ 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::Macro(..) => "macro",
+ 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::Fn(..) => format!("method {} in {}{}", ii.ident, path_str(), id_str),
+ ImplItemKind::TyAlias(_) => {
+ format!("assoc type {} in {}{}", ii.ident, path_str(), id_str)
+ }
+ },
+ Some(Node::TraitItem(ti)) => {
+ let kind = match ti.kind {
+ TraitItemKind::Const(..) => "assoc constant",
+ TraitItemKind::Fn(..) => "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(_)) => node_str("const"),
+ Some(Node::Expr(_)) => node_str("expr"),
+ Some(Node::Stmt(_)) => node_str("stmt"),
+ Some(Node::PathSegment(_)) => node_str("path segment"),
+ Some(Node::Ty(_)) => node_str("type"),
+ Some(Node::TypeBinding(_)) => node_str("type binding"),
+ Some(Node::TraitRef(_)) => node_str("trait ref"),
+ Some(Node::Pat(_)) => node_str("pat"),
+ Some(Node::Param(_)) => node_str("param"),
+ Some(Node::Arm(_)) => node_str("arm"),
+ Some(Node::Block(_)) => node_str("block"),
+ Some(Node::Infer(_)) => node_str("infer"),
+ Some(Node::Local(_)) => node_str("local"),
+ Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str),
+ Some(Node::Lifetime(_)) => node_str("lifetime"),
+ Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str),
+ Some(Node::Crate(..)) => String::from("root_crate"),
+ None => format!("unknown node{}", id_str),
+ }
+}
+
+pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems {
+ let mut collector = ItemCollector::new(tcx, false);
+
+ let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
+ collector.visit_mod(hir_mod, span, hir_id);
+
+ let ItemCollector {
+ submodules,
+ items,
+ trait_items,
+ impl_items,
+ foreign_items,
+ body_owners,
+ ..
+ } = collector;
+ return ModuleItems {
+ submodules: submodules.into_boxed_slice(),
+ items: items.into_boxed_slice(),
+ trait_items: trait_items.into_boxed_slice(),
+ impl_items: impl_items.into_boxed_slice(),
+ foreign_items: foreign_items.into_boxed_slice(),
+ body_owners: body_owners.into_boxed_slice(),
+ };
+}
+
+pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
+ let mut collector = ItemCollector::new(tcx, true);
+
+ // A "crate collector" and "module collector" start at a
+ // module item (the former starts at the crate root) but only
+ // the former needs to collect it. ItemCollector does not do this for us.
+ collector.submodules.push(CRATE_DEF_ID);
+ tcx.hir().walk_toplevel_module(&mut collector);
+
+ let ItemCollector {
+ submodules,
+ items,
+ trait_items,
+ impl_items,
+ foreign_items,
+ body_owners,
+ ..
+ } = collector;
+
+ return ModuleItems {
+ submodules: submodules.into_boxed_slice(),
+ items: items.into_boxed_slice(),
+ trait_items: trait_items.into_boxed_slice(),
+ impl_items: impl_items.into_boxed_slice(),
+ foreign_items: foreign_items.into_boxed_slice(),
+ body_owners: body_owners.into_boxed_slice(),
+ };
+}
+
+struct ItemCollector<'tcx> {
+ // When true, it collects all items in the create,
+ // otherwise it collects items in some module.
+ crate_collector: bool,
+ tcx: TyCtxt<'tcx>,
+ submodules: Vec<LocalDefId>,
+ items: Vec<ItemId>,
+ trait_items: Vec<TraitItemId>,
+ impl_items: Vec<ImplItemId>,
+ foreign_items: Vec<ForeignItemId>,
+ body_owners: Vec<LocalDefId>,
+}
+
+impl<'tcx> ItemCollector<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> {
+ ItemCollector {
+ crate_collector,
+ tcx,
+ submodules: Vec::default(),
+ items: Vec::default(),
+ trait_items: Vec::default(),
+ impl_items: Vec::default(),
+ foreign_items: Vec::default(),
+ body_owners: Vec::default(),
+ }
+ }
+}
+
+impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
+ type NestedFilter = nested_filter::All;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
+ }
+
+ fn visit_item(&mut self, item: &'hir Item<'hir>) {
+ if associated_body(Node::Item(item)).is_some() {
+ self.body_owners.push(item.def_id);
+ }
+
+ self.items.push(item.item_id());
+
+ // Items that are modules are handled here instead of in visit_mod.
+ if let ItemKind::Mod(module) = &item.kind {
+ self.submodules.push(item.def_id);
+ // A module collector does not recurse inside nested modules.
+ if self.crate_collector {
+ intravisit::walk_mod(self, module, item.hir_id());
+ }
+ } else {
+ intravisit::walk_item(self, item)
+ }
+ }
+
+ fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
+ self.foreign_items.push(item.foreign_item_id());
+ intravisit::walk_foreign_item(self, item)
+ }
+
+ fn visit_anon_const(&mut self, c: &'hir AnonConst) {
+ self.body_owners.push(self.tcx.hir().local_def_id(c.hir_id));
+ intravisit::walk_anon_const(self, c)
+ }
+
+ fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
+ if matches!(ex.kind, ExprKind::Closure { .. }) {
+ self.body_owners.push(self.tcx.hir().local_def_id(ex.hir_id));
+ }
+ intravisit::walk_expr(self, ex)
+ }
+
+ fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
+ if associated_body(Node::TraitItem(item)).is_some() {
+ self.body_owners.push(item.def_id);
+ }
+
+ self.trait_items.push(item.trait_item_id());
+ intravisit::walk_trait_item(self, item)
+ }
+
+ fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
+ if associated_body(Node::ImplItem(item)).is_some() {
+ self.body_owners.push(item.def_id);
+ }
+
+ self.impl_items.push(item.impl_item_id());
+ intravisit::walk_impl_item(self, item)
+ }
+}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
new file mode 100644
index 000000000..211a61471
--- /dev/null
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -0,0 +1,182 @@
+//! HIR datatypes. See the [rustc dev guide] for more info.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+
+pub mod map;
+pub mod nested_filter;
+pub mod place;
+
+use crate::ty::query::Providers;
+use crate::ty::{DefIdTree, ImplSubject, TyCtxt};
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::*;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_span::{ExpnId, DUMMY_SP};
+
+/// Top-level HIR node for current owner. This only contains the node for which
+/// `HirId::local_id == 0`, and excludes bodies.
+///
+/// This struct exists to encapsulate all access to the hir_owner query in this module, and to
+/// implement HashStable without hashing bodies.
+#[derive(Copy, Clone, Debug)]
+pub struct Owner<'tcx> {
+ node: OwnerNode<'tcx>,
+ hash_without_bodies: Fingerprint,
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ let Owner { node: _, hash_without_bodies } = self;
+ hash_without_bodies.hash_stable(hcx, hasher)
+ }
+}
+
+/// Gather the LocalDefId for each item-like within a module, including items contained within
+/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
+#[derive(Debug, HashStable, Encodable, Decodable)]
+pub struct ModuleItems {
+ submodules: Box<[LocalDefId]>,
+ items: Box<[ItemId]>,
+ trait_items: Box<[TraitItemId]>,
+ impl_items: Box<[ImplItemId]>,
+ foreign_items: Box<[ForeignItemId]>,
+ body_owners: Box<[LocalDefId]>,
+}
+
+impl ModuleItems {
+ pub fn items(&self) -> impl Iterator<Item = ItemId> + '_ {
+ self.items.iter().copied()
+ }
+
+ pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ {
+ self.trait_items.iter().copied()
+ }
+
+ pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> + '_ {
+ self.impl_items.iter().copied()
+ }
+
+ pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> + '_ {
+ self.foreign_items.iter().copied()
+ }
+
+ pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+ self.items
+ .iter()
+ .map(|id| id.def_id)
+ .chain(self.trait_items.iter().map(|id| id.def_id))
+ .chain(self.impl_items.iter().map(|id| id.def_id))
+ .chain(self.foreign_items.iter().map(|id| id.def_id))
+ }
+
+ pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
+ par_for_each_in(&self.items[..], |&id| f(id))
+ }
+
+ pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + Send + Sync) {
+ par_for_each_in(&self.trait_items[..], |&id| f(id))
+ }
+
+ pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + Send + Sync) {
+ par_for_each_in(&self.impl_items[..], |&id| f(id))
+ }
+
+ pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + Send + Sync) {
+ par_for_each_in(&self.foreign_items[..], |&id| f(id))
+ }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ #[inline(always)]
+ pub fn hir(self) -> map::Map<'tcx> {
+ map::Map { tcx: self }
+ }
+
+ pub fn parent_module(self, id: HirId) -> LocalDefId {
+ self.parent_module_from_def_id(id.owner)
+ }
+
+ pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
+ self.impl_trait_ref(def_id)
+ .map(ImplSubject::Trait)
+ .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
+ }
+}
+
+pub fn provide(providers: &mut Providers) {
+ providers.parent_module_from_def_id = |tcx, id| {
+ let hir = tcx.hir();
+ hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
+ };
+ providers.hir_crate_items = map::hir_crate_items;
+ providers.crate_hash = map::crate_hash;
+ providers.hir_module_items = map::hir_module_items;
+ providers.hir_owner = |tcx, id| {
+ let owner = tcx.hir_crate(()).owners.get(id)?.as_owner()?;
+ let node = owner.node();
+ Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
+ };
+ providers.local_def_id_to_hir_id = |tcx, id| {
+ let owner = tcx.hir_crate(()).owners[id].map(|_| ());
+ match owner {
+ MaybeOwner::Owner(_) => HirId::make_owner(id),
+ MaybeOwner::Phantom => bug!("No HirId for {:?}", id),
+ MaybeOwner::NonOwner(hir_id) => hir_id,
+ }
+ };
+ providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].map(|i| &i.nodes);
+ providers.hir_owner_parent = |tcx, id| {
+ // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
+ tcx.opt_local_parent(id).map_or(CRATE_HIR_ID, |parent| {
+ let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent);
+ if let Some(local_id) =
+ tcx.hir_crate(()).owners[parent_hir_id.owner].unwrap().parenting.get(&id)
+ {
+ parent_hir_id.local_id = *local_id;
+ }
+ parent_hir_id
+ })
+ };
+ providers.hir_attrs =
+ |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs);
+ providers.source_span =
+ |tcx, def_id| tcx.resolutions(()).source_span.get(def_id).copied().unwrap_or(DUMMY_SP);
+ providers.def_span = |tcx, def_id| {
+ let def_id = def_id.expect_local();
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP)
+ };
+ providers.def_ident_span = |tcx, def_id| {
+ let def_id = def_id.expect_local();
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ tcx.hir().opt_ident_span(hir_id)
+ };
+ providers.fn_arg_names = |tcx, id| {
+ let hir = tcx.hir();
+ let def_id = id.expect_local();
+ let hir_id = hir.local_def_id_to_hir_id(def_id);
+ if let Some(body_id) = hir.maybe_body_owned_by(def_id) {
+ tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
+ } else if let Node::TraitItem(&TraitItem {
+ kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
+ ..
+ }) = hir.get(hir_id)
+ {
+ tcx.arena.alloc_slice(idents)
+ } else {
+ span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
+ }
+ };
+ providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
+ providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
+ providers.expn_that_defined = |tcx, id| {
+ let id = id.expect_local();
+ tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
+ };
+ providers.in_scope_traits_map =
+ |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map(|owner_info| &owner_info.trait_map);
+}
diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs
new file mode 100644
index 000000000..6896837aa
--- /dev/null
+++ b/compiler/rustc_middle/src/hir/nested_filter.rs
@@ -0,0 +1,31 @@
+use rustc_hir::intravisit::nested_filter::NestedFilter;
+
+/// Do not visit nested item-like things, but visit nested things
+/// that are inside of an item-like.
+///
+/// Notably, possible occurrences of bodies in non-item-like things
+/// include: closures/generators, inline `const {}` blocks, and
+/// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
+///
+/// **This is the most common choice.** A very common pattern is
+/// to use `visit_all_item_likes_in_crate()` as an outer loop,
+/// and to have the visitor that visits the contents of each item
+/// using this setting.
+pub struct OnlyBodies(());
+impl<'hir> NestedFilter<'hir> for OnlyBodies {
+ type Map = crate::hir::map::Map<'hir>;
+ const INTER: bool = false;
+ const INTRA: bool = true;
+}
+
+/// Visits all nested things, including item-likes.
+///
+/// **This is an unusual choice.** It is used when you want to
+/// process everything within their lexical context. Typically you
+/// kick off the visit by doing `walk_krate()`.
+pub struct All(());
+impl<'hir> NestedFilter<'hir> for All {
+ type Map = crate::hir::map::Map<'hir>;
+ const INTER: bool = true;
+ const INTRA: bool = true;
+}
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
new file mode 100644
index 000000000..83d3b0100
--- /dev/null
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -0,0 +1,117 @@
+use crate::ty;
+use crate::ty::Ty;
+
+use rustc_hir::HirId;
+use rustc_target::abi::VariantIdx;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum PlaceBase {
+ /// A temporary variable.
+ Rvalue,
+ /// A named `static` item.
+ StaticItem,
+ /// A named local variable.
+ Local(HirId),
+ /// An upvar referenced by closure env.
+ Upvar(ty::UpvarId),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum ProjectionKind {
+ /// A dereference of a pointer, reference or `Box<T>` of the given type.
+ Deref,
+
+ /// `B.F` where `B` is the base expression and `F` is
+ /// the field. The field is identified by which variant
+ /// it appears in along with a field index. The variant
+ /// is used for enums.
+ Field(u32, VariantIdx),
+
+ /// Some index like `B[x]`, where `B` is the base
+ /// expression. We don't preserve the index `x` because
+ /// we won't need it.
+ Index,
+
+ /// A subslice covering a range of values like `B[x..y]`.
+ Subslice,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct Projection<'tcx> {
+ /// Type after the projection is applied.
+ pub ty: Ty<'tcx>,
+
+ /// Defines the kind of access made by the projection.
+ pub kind: ProjectionKind,
+}
+
+/// A `Place` represents how a value is located in memory.
+///
+/// This is an HIR version of [`rustc_middle::mir::Place`].
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct Place<'tcx> {
+ /// The type of the `PlaceBase`
+ pub base_ty: Ty<'tcx>,
+ /// The "outermost" place that holds this value.
+ pub base: PlaceBase,
+ /// How this place is derived from the base place.
+ pub projections: Vec<Projection<'tcx>>,
+}
+
+/// A `PlaceWithHirId` represents how a value is located in memory.
+///
+/// This is an HIR version of [`rustc_middle::mir::Place`].
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct PlaceWithHirId<'tcx> {
+ /// `HirId` of the expression or pattern producing this value.
+ pub hir_id: HirId,
+
+ /// Information about the `Place`.
+ pub place: Place<'tcx>,
+}
+
+impl<'tcx> PlaceWithHirId<'tcx> {
+ pub fn new(
+ hir_id: HirId,
+ base_ty: Ty<'tcx>,
+ base: PlaceBase,
+ projections: Vec<Projection<'tcx>>,
+ ) -> PlaceWithHirId<'tcx> {
+ PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } }
+ }
+}
+
+impl<'tcx> Place<'tcx> {
+ /// Returns an iterator of the types that have to be dereferenced to access
+ /// the `Place`.
+ ///
+ /// The types are in the reverse order that they are applied. So if
+ /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
+ ///`*const u32` then `&*const u32`.
+ pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
+ self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
+ if ProjectionKind::Deref == proj.kind {
+ Some(self.ty_before_projection(index))
+ } else {
+ None
+ }
+ })
+ }
+
+ /// Returns the type of this `Place` after all projections have been applied.
+ pub fn ty(&self) -> Ty<'tcx> {
+ self.projections.last().map_or(self.base_ty, |proj| proj.ty)
+ }
+
+ /// Returns the type of this `Place` immediately before `projection_index`th projection
+ /// is applied.
+ pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
+ assert!(projection_index < self.projections.len());
+ if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
+ }
+}
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
new file mode 100644
index 000000000..200de9079
--- /dev/null
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -0,0 +1,363 @@
+//! **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 dev guide][c].
+//!
+//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
+
+use crate::infer::MemberConstraint;
+use crate::ty::subst::GenericArg;
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
+use rustc_index::vec::IndexVec;
+use rustc_macros::HashStable;
+use smallvec::SmallVec;
+use std::iter;
+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, TyDecodable, TyEncodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, 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<'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, TyDecodable, TyEncodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, 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 all queries except `evaluate_goal` (used by Chalk),
+ /// 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<'tcx> 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, TyDecodable, TyEncodable, HashStable)]
+pub struct CanonicalVarInfo<'tcx> {
+ pub kind: CanonicalVarKind<'tcx>,
+}
+
+impl<'tcx> CanonicalVarInfo<'tcx> {
+ 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, TyDecodable, TyEncodable, HashStable)]
+pub enum CanonicalVarKind<'tcx> {
+ /// 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, Ty<'tcx>),
+
+ /// A "placeholder" that represents "any const".
+ PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
+}
+
+impl<'tcx> CanonicalVarKind<'tcx> {
+ 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, TyDecodable, TyEncodable, 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, TypeVisitable, Lift)]
+pub struct QueryResponse<'tcx, R> {
+ pub var_values: CanonicalVarValues<'tcx>,
+ pub region_constraints: QueryRegionConstraints<'tcx>,
+ pub certainty: Certainty,
+ /// List of opaque types which we tried to compare to another type.
+ /// Inside the query we don't know yet whether the opaque type actually
+ /// should get its hidden type inferred. So we bubble the opaque type
+ /// and the type it was compared against upwards and let the query caller
+ /// handle it.
+ pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
+ pub value: R,
+}
+
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, 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 unification 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,
+ }
+ }
+}
+
+impl<'tcx, R> QueryResponse<'tcx, R> {
+ pub fn is_proven(&self) -> bool {
+ self.certainty.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, R> Canonical<'tcx, ty::ParamEnvAnd<'tcx, R>> {
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.value = self.value.without_const();
+ self
+ }
+}
+
+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<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
+
+TrivialTypeTraversalAndLiftImpls! {
+ for <'tcx> {
+ crate::infer::canonical::Certainty,
+ crate::infer::canonical::CanonicalVarInfo<'tcx>,
+ crate::infer::canonical::CanonicalVarKind<'tcx>,
+ }
+}
+
+TrivialTypeTraversalImpls! {
+ for <'tcx> {
+ crate::infer::canonical::CanonicalVarInfos<'tcx>,
+ }
+}
+
+impl<'tcx> CanonicalVarValues<'tcx> {
+ #[inline]
+ 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: iter::zip(&self.var_values, 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(..) => {
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+ }
+ GenericArgKind::Const(ct) => tcx
+ .mk_const(ty::ConstS {
+ ty: ct.ty(),
+ kind: 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/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs
new file mode 100644
index 000000000..38868c210
--- /dev/null
+++ b/compiler/rustc_middle/src/infer/mod.rs
@@ -0,0 +1,32 @@
+pub mod canonical;
+pub mod unify_key;
+
+use crate::ty::Region;
+use crate::ty::{OpaqueTypeKey, Ty};
+use rustc_data_structures::sync::Lrc;
+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:
+///
+/// ```text
+/// R0 member of [O1..On]
+/// ```
+#[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct MemberConstraint<'tcx> {
+ /// The `DefId` and substs of the opaque type causing this constraint.
+ /// Used for error reporting.
+ pub key: OpaqueTypeKey<'tcx>,
+
+ /// 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/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
new file mode 100644
index 000000000..f2627885d
--- /dev/null
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -0,0 +1,162 @@
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
+use rustc_span::def_id::DefId;
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
+use std::cmp;
+use std::marker::PhantomData;
+
+pub trait ToType {
+ fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
+}
+
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);
+
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct RegionVidKey<'tcx> {
+ pub vid: ty::RegionVid,
+ pub phantom: PhantomData<UnifiedRegion<'tcx>>,
+}
+
+impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
+ fn from(vid: ty::RegionVid) -> Self {
+ RegionVidKey { vid, phantom: PhantomData }
+ }
+}
+
+impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
+ type Value = UnifiedRegion<'tcx>;
+ #[inline]
+ fn index(&self) -> u32 {
+ self.vid.as_u32()
+ }
+ #[inline]
+ fn from_index(i: u32) -> Self {
+ RegionVidKey::from(ty::RegionVid::from_u32(i))
+ }
+ fn tag() -> &'static str {
+ "RegionVidKey"
+ }
+}
+
+impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
+ type Error = NoError;
+
+ fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
+ Ok(match (value1.0, value2.0) {
+ // Here we can just pick one value, because the full constraints graph
+ // will be handled later. Ideally, we might want a `MultipleValues`
+ // variant or something. For now though, this is fine.
+ (Some(_), Some(_)) => *value1,
+
+ (Some(_), _) => *value1,
+ (_, Some(_)) => *value2,
+
+ (None, None) => *value1,
+ })
+ }
+}
+
+impl ToType for ty::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),
+ }
+ }
+}
+
+impl ToType for ty::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, DefId),
+ SubstitutionPlaceholder,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum ConstVariableValue<'tcx> {
+ Known { value: 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<ty::Const<'tcx>> {
+ match *self {
+ ConstVariableValue::Unknown { .. } => None,
+ ConstVariableValue::Known { value } => Some(value),
+ }
+ }
+}
+
+#[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>;
+ #[inline]
+ fn index(&self) -> u32 {
+ self.index
+ }
+ #[inline]
+ 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 = (ty::Const<'tcx>, ty::Const<'tcx>);
+
+ fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
+ Ok(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 { .. }) => value1,
+ (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
+
+ // 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);
+ ConstVarValue {
+ val: ConstVariableValue::Unknown { universe },
+ origin: value1.origin,
+ }
+ }
+ })
+ }
+}
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
new file mode 100644
index 000000000..ef06c457b
--- /dev/null
+++ b/compiler/rustc_middle/src/lib.rs
@@ -0,0 +1,106 @@
+//! 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 `rustc_const_eval` 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 dev guide].
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(allocator_api)]
+#![feature(array_windows)]
+#![feature(assert_matches)]
+#![feature(backtrace)]
+#![feature(box_patterns)]
+#![feature(core_intrinsics)]
+#![feature(discriminant_kind)]
+#![feature(exhaustive_patterns)]
+#![feature(get_mut_unchecked)]
+#![feature(generic_associated_types)]
+#![feature(if_let_guard)]
+#![feature(map_first_last)]
+#![feature(negative_impls)]
+#![feature(never_type)]
+#![feature(extern_types)]
+#![feature(new_uninit)]
+#![feature(once_cell)]
+#![feature(let_chains)]
+#![feature(let_else)]
+#![feature(min_specialization)]
+#![feature(trusted_len)]
+#![feature(type_alias_impl_trait)]
+#![feature(associated_type_bounds)]
+#![feature(rustc_attrs)]
+#![feature(half_open_range_patterns)]
+#![feature(control_flow_enum)]
+#![feature(associated_type_defaults)]
+#![feature(trusted_step)]
+#![feature(try_blocks)]
+#![feature(try_reserve_kind)]
+#![feature(nonzero_ops)]
+#![feature(unwrap_infallible)]
+#![feature(decl_macro)]
+#![feature(drain_filter)]
+#![feature(intra_doc_pointers)]
+#![feature(yeet_expr)]
+#![feature(const_option)]
+#![recursion_limit = "512"]
+#![allow(rustc::potential_query_instability)]
+
+#[macro_use]
+extern crate bitflags;
+#[macro_use]
+extern crate rustc_macros;
+#[macro_use]
+extern crate rustc_data_structures;
+#[macro_use]
+extern crate tracing;
+#[macro_use]
+extern crate smallvec;
+
+#[cfg(test)]
+mod tests;
+
+#[macro_use]
+mod macros;
+
+#[macro_use]
+pub mod query;
+
+#[macro_use]
+pub mod arena;
+#[macro_use]
+pub mod dep_graph;
+pub mod hir;
+pub mod infer;
+pub mod lint;
+pub mod metadata;
+pub mod middle;
+pub mod mir;
+pub mod thir;
+pub mod traits;
+pub mod ty;
+
+pub mod util {
+ pub mod bug;
+ pub mod common;
+}
+
+// Allows macros to refer to this crate as `::rustc_middle`
+extern crate self as rustc_middle;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
new file mode 100644
index 000000000..2f45222de
--- /dev/null
+++ b/compiler/rustc_middle/src/lint.rs
@@ -0,0 +1,443 @@
+use std::cmp;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan};
+use rustc_hir::HirId;
+use rustc_index::vec::IndexVec;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_session::lint::{
+ builtin::{self, FORBIDDEN_LINT_GROUPS},
+ FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId,
+};
+use rustc_session::Session;
+use rustc_span::hygiene::MacroKind;
+use rustc_span::source_map::{DesugaringKind, ExpnKind};
+use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
+
+/// How a lint level was set.
+#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
+pub enum LintLevelSource {
+ /// 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.
+ /// The provided `Level` is the level specified on the command line.
+ /// (The actual level may be lower due to `--cap-lints`.)
+ CommandLine(Symbol, Level),
+}
+
+impl LintLevelSource {
+ pub fn name(&self) -> Symbol {
+ match *self {
+ LintLevelSource::Default => symbol::kw::Default,
+ LintLevelSource::Node(name, _, _) => name,
+ LintLevelSource::CommandLine(name, _) => name,
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match *self {
+ LintLevelSource::Default => DUMMY_SP,
+ LintLevelSource::Node(_, span, _) => span,
+ LintLevelSource::CommandLine(_, _) => DUMMY_SP,
+ }
+ }
+}
+
+/// A tuple of a lint level and its source.
+pub type LevelAndSource = (Level, LintLevelSource);
+
+#[derive(Debug, HashStable)]
+pub struct LintLevelSets {
+ pub list: IndexVec<LintStackIndex, LintSet>,
+ pub lint_cap: Level,
+}
+
+rustc_index::newtype_index! {
+ #[derive(HashStable)]
+ pub struct LintStackIndex {
+ const COMMAND_LINE = 0,
+ }
+}
+
+#[derive(Debug, HashStable)]
+pub struct LintSet {
+ // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
+ // flag.
+ pub specs: FxHashMap<LintId, LevelAndSource>,
+
+ pub parent: LintStackIndex,
+}
+
+impl LintLevelSets {
+ pub fn new() -> Self {
+ LintLevelSets { list: IndexVec::new(), lint_cap: Level::Forbid }
+ }
+
+ pub fn get_lint_level(
+ &self,
+ lint: &'static Lint,
+ idx: LintStackIndex,
+ aux: Option<&FxHashMap<LintId, LevelAndSource>>,
+ sess: &Session,
+ ) -> LevelAndSource {
+ 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.
+ //
+ // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
+ // triggers in cases (like #80988) where you have `forbid(warnings)`,
+ // and so if we turned that into an error, it'd defeat the purpose of the
+ // future compatibility warning.
+ if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) {
+ 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
+ // unless the source is a --force-warn
+ level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src {
+ level
+ } else {
+ 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);
+ }
+
+ (level, src)
+ }
+
+ pub fn get_lint_id_level(
+ &self,
+ id: LintId,
+ mut idx: LintStackIndex,
+ aux: Option<&FxHashMap<LintId, LevelAndSource>>,
+ ) -> (Option<Level>, LintLevelSource) {
+ if let Some(specs) = aux {
+ if let Some(&(level, src)) = specs.get(&id) {
+ return (Some(level), src);
+ }
+ }
+ loop {
+ let LintSet { ref specs, parent } = self.list[idx];
+ if let Some(&(level, src)) = specs.get(&id) {
+ return (Some(level), src);
+ }
+ if idx == COMMAND_LINE {
+ return (None, LintLevelSource::Default);
+ }
+ idx = parent;
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct LintLevelMap {
+ /// This is a collection of lint expectations as described in RFC 2383, that
+ /// can be fulfilled during this compilation session. This means that at least
+ /// one expected lint is currently registered in the lint store.
+ ///
+ /// The [`LintExpectationId`] is stored as a part of the [`Expect`](Level::Expect)
+ /// lint level.
+ pub lint_expectations: Vec<(LintExpectationId, LintExpectation)>,
+ pub sets: LintLevelSets,
+ pub id_to_set: FxHashMap<HirId, LintStackIndex>,
+}
+
+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<LevelAndSource> {
+ 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, ref lint_expectations } = *self;
+
+ id_to_set.hash_stable(hcx, hasher);
+ lint_expectations.hash_stable(hcx, hasher);
+
+ hcx.while_hashing_spans(true, |hcx| sets.hash_stable(hcx, hasher))
+ }
+}
+
+/// This struct represents a lint expectation and holds all required information
+/// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
+/// the `LateLintPass` has completed.
+#[derive(Clone, Debug, HashStable)]
+pub struct LintExpectation {
+ /// The reason for this expectation that can optionally be added as part of
+ /// the attribute. It will be displayed as part of the lint message.
+ pub reason: Option<Symbol>,
+ /// The [`Span`] of the attribute that this expectation originated from.
+ pub emission_span: Span,
+ /// Lint messages for the `unfulfilled_lint_expectations` lint will be
+ /// adjusted to include an additional note. Therefore, we have to track if
+ /// the expectation is for the lint.
+ pub is_unfulfilled_lint_expectations: bool,
+ /// This will hold the name of the tool that this lint belongs to. For
+ /// the lint `clippy::some_lint` the tool would be `clippy`, the same
+ /// goes for `rustdoc`. This will be `None` for rustc lints
+ pub lint_tool: Option<Symbol>,
+}
+
+impl LintExpectation {
+ pub fn new(
+ reason: Option<Symbol>,
+ emission_span: Span,
+ is_unfulfilled_lint_expectations: bool,
+ lint_tool: Option<Symbol>,
+ ) -> Self {
+ Self { reason, emission_span, is_unfulfilled_lint_expectations, lint_tool }
+ }
+}
+
+pub fn explain_lint_level_source(
+ lint: &'static Lint,
+ level: Level,
+ src: LintLevelSource,
+ err: &mut Diagnostic,
+) {
+ let name = lint.name_lower();
+ match src {
+ LintLevelSource::Default => {
+ err.note_once(&format!("`#[{}({})]` on by default", level.as_str(), name));
+ }
+ LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
+ let flag = match orig_level {
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ Level::Allow => "-A",
+ Level::ForceWarn(_) => "--force-warn",
+ Level::Expect(_) => {
+ unreachable!("the expect level does not have a commandline flag")
+ }
+ };
+ let hyphen_case_lint_name = name.replace('_', "-");
+ if lint_flag_val.as_str() == name {
+ err.note_once(&format!(
+ "requested on the command line with `{} {}`",
+ flag, hyphen_case_lint_name
+ ));
+ } else {
+ let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
+ err.note_once(&format!(
+ "`{} {}` implied by `{} {}`",
+ flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
+ ));
+ }
+ }
+ LintLevelSource::Node(lint_attr_name, src, reason) => {
+ if let Some(rationale) = reason {
+ err.note(rationale.as_str());
+ }
+ err.span_note_once(src, "the lint level is defined here");
+ if lint_attr_name.as_str() != name {
+ let level_str = level.as_str();
+ err.note_once(&format!(
+ "`#[{}({})]` implied by `#[{}({})]`",
+ level_str, name, level_str, lint_attr_name
+ ));
+ }
+ }
+ }
+}
+
+pub fn struct_lint_level<'s, 'd>(
+ sess: &'s Session,
+ lint: &'static Lint,
+ level: Level,
+ src: LintLevelSource,
+ 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<'s, 'd>(
+ sess: &'s Session,
+ lint: &'static Lint,
+ level: Level,
+ src: LintLevelSource,
+ span: Option<MultiSpan>,
+ decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) + 'd>,
+ ) {
+ // Check for future incompatibility lints and issue a stronger warning.
+ let future_incompatible = lint.future_incompatible;
+
+ let has_future_breakage = future_incompatible.map_or(
+ // Default allow lints trigger too often for testing.
+ sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow,
+ |incompat| {
+ matches!(incompat.reason, FutureIncompatibilityReason::FutureReleaseErrorReportNow)
+ },
+ );
+
+ let mut err = match (level, span) {
+ (Level::Allow, span) => {
+ if has_future_breakage {
+ if let Some(span) = span {
+ sess.struct_span_allow(span, "")
+ } else {
+ sess.struct_allow("")
+ }
+ } else {
+ return;
+ }
+ }
+ (Level::Expect(expect_id), _) => {
+ // This case is special as we actually allow the lint itself in this context, but
+ // we can't return early like in the case for `Level::Allow` because we still
+ // need the lint diagnostic to be emitted to `rustc_error::HandlerInner`.
+ //
+ // We can also not mark the lint expectation as fulfilled here right away, as it
+ // can still be cancelled in the decorate function. All of this means that we simply
+ // create a `DiagnosticBuilder` and continue as we would for warnings.
+ sess.struct_expect("", expect_id)
+ }
+ (Level::ForceWarn(Some(expect_id)), Some(span)) => {
+ sess.struct_span_warn_with_expectation(span, "", expect_id)
+ }
+ (Level::ForceWarn(Some(expect_id)), None) => {
+ sess.struct_warn_with_expectation("", expect_id)
+ }
+ (Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""),
+ (Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""),
+ (Level::Deny | Level::Forbid, Some(span)) => {
+ let mut builder = sess.diagnostic().struct_err_lint("");
+ builder.set_span(span);
+ builder
+ }
+ (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
+ };
+
+ // 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.disable_suggestions();
+
+ // If this is a future incompatible that is not an edition fixing lint
+ // it'll become a hard error, so we have to emit *something*. Also,
+ // if this lint occurs in the expansion of a macro from an external crate,
+ // allow individual lints to opt-out from being reported.
+ let not_future_incompatible =
+ future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true);
+ if not_future_incompatible && !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;
+ }
+ }
+
+ // Lint diagnostics that are covered by the expect level will not be emitted outside
+ // the compiler. It is therefore not necessary to add any information for the user.
+ // This will therefore directly call the decorate function which will in turn emit
+ // the `Diagnostic`.
+ if let Level::Expect(_) = level {
+ let name = lint.name_lower();
+ err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
+ decorate(LintDiagnosticBuilder::new(err));
+ return;
+ }
+
+ explain_lint_level_source(lint, level, src, &mut err);
+
+ let name = lint.name_lower();
+ let is_force_warn = matches!(level, Level::ForceWarn(_));
+ err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
+
+ if let Some(future_incompatible) = future_incompatible {
+ let explanation = match future_incompatible.reason {
+ FutureIncompatibilityReason::FutureReleaseError
+ | FutureIncompatibilityReason::FutureReleaseErrorReportNow => {
+ "this was previously accepted by the compiler but is being phased out; \
+ it will become a hard error in a future release!"
+ .to_owned()
+ }
+ FutureIncompatibilityReason::FutureReleaseSemanticsChange => {
+ "this will change its meaning in a future release!".to_owned()
+ }
+ FutureIncompatibilityReason::EditionError(edition) => {
+ let current_edition = sess.edition();
+ format!(
+ "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!",
+ current_edition, edition
+ )
+ }
+ FutureIncompatibilityReason::EditionSemanticsChange(edition) => {
+ format!("this changes meaning in Rust {}", edition)
+ }
+ FutureIncompatibilityReason::Custom(reason) => reason.to_owned(),
+ };
+
+ if future_incompatible.explain_reason {
+ err.warn(&explanation);
+ }
+ if !future_incompatible.reference.is_empty() {
+ let citation =
+ format!("for more information, see {}", future_incompatible.reference);
+ 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::Inlined
+ | ExpnKind::Root
+ | ExpnKind::Desugaring(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) => false,
+ ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
+ ExpnKind::Macro(MacroKind::Bang, _) => {
+ // Dummy span for the `def_site` means it's an external macro.
+ expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
+ }
+ ExpnKind::Macro { .. } => true, // definitely a plugin
+ }
+}
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
new file mode 100644
index 000000000..0e85c60a3
--- /dev/null
+++ b/compiler/rustc_middle/src/macros.rs
@@ -0,0 +1,232 @@
+#[macro_export]
+macro_rules! bug {
+ () => ( $crate::bug!("impossible case reached") );
+ ($msg:expr) => ({ $crate::util::bug::bug_fmt(::std::format_args!($msg)) });
+ ($msg:expr,) => ({ $crate::bug!($msg) });
+ ($fmt:expr, $($arg:tt)+) => ({
+ $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+))
+ });
+}
+
+#[macro_export]
+macro_rules! span_bug {
+ ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) });
+ ($span:expr, $msg:expr,) => ({ $crate::span_bug!($span, $msg) });
+ ($span:expr, $fmt:expr, $($arg:tt)+) => ({
+ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+))
+ });
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Lift and TypeFoldable/TypeVisitable 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(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! TrivialTypeTraversalImpls {
+ (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+ $(
+ impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
+ fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
+ self,
+ _: &mut F
+ ) -> ::std::result::Result<$ty, F::Error> {
+ Ok(self)
+ }
+ }
+
+ impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty {
+ fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
+ &self,
+ _: &mut F)
+ -> ::std::ops::ControlFlow<F::BreakTy>
+ {
+ ::std::ops::ControlFlow::CONTINUE
+ }
+ }
+ )+
+ };
+
+ ($($ty:ty,)+) => {
+ TrivialTypeTraversalImpls! {
+ for <'tcx> {
+ $($ty,)+
+ }
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! TrivialTypeTraversalAndLiftImpls {
+ ($($t:tt)*) => {
+ TrivialTypeTraversalImpls! { $($t)* }
+ CloneLiftImpls! { $($t)* }
+ }
+}
+
+#[macro_export]
+macro_rules! EnumTypeTraversalImpl {
+ (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 try_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
+ self,
+ folder: &mut V,
+ ) -> ::std::result::Result<Self, V::Error> {
+ EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
+ }
+ }
+ };
+
+ (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path {
+ $($variants:tt)*
+ } $(where $($wc:tt)*)*) => {
+ impl<$($p),*> $crate::ty::visit::TypeVisitable<$tcx> for $s
+ $(where $($wc)*)*
+ {
+ fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>(
+ &self,
+ visitor: &mut V,
+ ) -> ::std::ops::ControlFlow<V::BreakTy> {
+ EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
+ }
+ }
+ };
+
+ (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
+ Ok(match $this {
+ $($output)*
+ })
+ };
+
+ (@FoldVariants($this:expr, $folder:expr)
+ input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
+ output( $($output:tt)*) ) => {
+ EnumTypeTraversalImpl!(
+ @FoldVariants($this, $folder)
+ input($($input)*)
+ output(
+ $variant ( $($variant_arg),* ) => {
+ $variant (
+ $($crate::ty::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
+ )
+ }
+ $($output)*
+ )
+ )
+ };
+
+ (@FoldVariants($this:expr, $folder:expr)
+ input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
+ output( $($output:tt)*) ) => {
+ EnumTypeTraversalImpl!(
+ @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)*) ) => {
+ EnumTypeTraversalImpl!(
+ @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)*) ) => {
+ EnumTypeTraversalImpl!(
+ @VisitVariants($this, $visitor)
+ input($($input)*)
+ output(
+ $variant ( $($variant_arg),* ) => {
+ $($crate::ty::visit::TypeVisitable::visit_with(
+ $variant_arg, $visitor
+ )?;)*
+ ::std::ops::ControlFlow::CONTINUE
+ }
+ $($output)*
+ )
+ )
+ };
+
+ (@VisitVariants($this:expr, $visitor:expr)
+ input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
+ output( $($output:tt)*) ) => {
+ EnumTypeTraversalImpl!(
+ @VisitVariants($this, $visitor)
+ input($($input)*)
+ output(
+ $variant { $($variant_arg),* } => {
+ $($crate::ty::visit::TypeVisitable::visit_with(
+ $variant_arg, $visitor
+ )?;)*
+ ::std::ops::ControlFlow::CONTINUE
+ }
+ $($output)*
+ )
+ )
+ };
+
+ (@VisitVariants($this:expr, $visitor:expr)
+ input( ($variant:path), $($input:tt)*)
+ output( $($output:tt)*) ) => {
+ EnumTypeTraversalImpl!(
+ @VisitVariants($this, $visitor)
+ input($($input)*)
+ output(
+ $variant => { ::std::ops::ControlFlow::CONTINUE }
+ $($output)*
+ )
+ )
+ };
+}
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
new file mode 100644
index 000000000..c8e78747d
--- /dev/null
+++ b/compiler/rustc_middle/src/metadata.rs
@@ -0,0 +1,26 @@
+use crate::ty;
+
+use rustc_hir::def::Res;
+use rustc_macros::HashStable;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates
+/// during name resolution. Right now the bindings are not recreated entirely precisely so we may
+/// need to add more data in the future to correctly support macros 2.0, for example.
+/// Module child can be either a proper item or a reexport (including private imports).
+/// In case of reexport all the fields describe the reexport item itself, not what it refers to.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ModChild {
+ /// Name of the item.
+ pub ident: Ident,
+ /// Resolution result corresponding to the item.
+ /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
+ pub res: Res<!>,
+ /// Visibility of the item.
+ pub vis: ty::Visibility,
+ /// Span of the item.
+ pub span: Span,
+ /// A proper `macro_rules` item (not a reexport).
+ pub macro_rules: bool,
+}
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
new file mode 100644
index 000000000..45d33a165
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -0,0 +1,146 @@
+use crate::mir::mono::Linkage;
+use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_span::symbol::Symbol;
+use rustc_target::spec::SanitizerSet;
+
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
+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<u16>,
+ /// 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>,
+ /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
+ /// instrumentation should be disabled inside the annotated function.
+ pub no_sanitize: SanitizerSet,
+ /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
+ /// be generated against a specific instruction set. Only usable on architectures which allow
+ /// switching between multiple instruction sets.
+ pub instruction_set: Option<InstructionSetAttr>,
+ /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
+ /// aligned to.
+ pub alignment: Option<u32>,
+}
+
+bitflags! {
+ #[derive(TyEncodable, TyDecodable, 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 and the function has no side effects other than allocating.
+ const ALLOCATOR = 1 << 1;
+ /// An indicator that function will never unwind. Will become obsolete
+ /// once C-unwind is fully stabilized.
+ const NEVER_UNWIND = 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;
+ /// `#[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;
+ /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
+ /// declaration.
+ const FFI_PURE = 1 << 12;
+ /// #[ffi_const]: applies clang's `const` attribute to a foreign function
+ /// declaration.
+ const FFI_CONST = 1 << 13;
+ /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
+ /// function as an entry function from Non-Secure code.
+ const CMSE_NONSECURE_ENTRY = 1 << 14;
+ /// `#[no_coverage]`: indicates that the function should be ignored by
+ /// the MIR `InstrumentCoverage` pass and not added to the coverage map
+ /// during codegen.
+ const NO_COVERAGE = 1 << 15;
+ /// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function.
+ const USED_LINKER = 1 << 16;
+ /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
+ const DEALLOCATOR = 1 << 17;
+ /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
+ const REALLOCATOR = 1 << 18;
+ /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
+ const ALLOCATOR_ZEROED = 1 << 19;
+ }
+}
+
+impl CodegenFnAttrs {
+ pub const EMPTY: &'static Self = &Self::new();
+
+ pub const 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,
+ no_sanitize: SanitizerSet::empty(),
+ instruction_set: None,
+ alignment: 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 | Linkage::Private) => false,
+ Some(_) => true,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs
new file mode 100644
index 000000000..e079843bf
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/dependency_format.rs
@@ -0,0 +1,28 @@
+//! 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 rustc_session::config::CrateType;
+
+/// 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<(CrateType, DependencyList)>;
+
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Encodable, Decodable)]
+pub enum Linkage {
+ NotLinked,
+ IncludedFromDylib,
+ Static,
+ Dynamic,
+}
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
new file mode 100644
index 000000000..631fd09ec
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -0,0 +1,72 @@
+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, TyEncodable, TyDecodable, 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
+ }
+}
+
+/// Kind of exported symbols.
+#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)]
+pub enum SymbolExportKind {
+ Text,
+ Data,
+ Tls,
+}
+
+/// The `SymbolExportInfo` of a symbols specifies symbol-related information
+/// that is relevant to code generation and linking.
+#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub struct SymbolExportInfo {
+ pub level: SymbolExportLevel,
+ pub kind: SymbolExportKind,
+ pub used: bool,
+}
+
+#[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub enum ExportedSymbol<'tcx> {
+ NonGeneric(DefId),
+ Generic(DefId, SubstsRef<'tcx>),
+ DropGlue(Ty<'tcx>),
+ NoDefId(ty::SymbolName<'tcx>),
+}
+
+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<'tcx> {
+ 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_{}_{:08x}",
+ tcx.crate_name(LOCAL_CRATE),
+ tcx.sess.local_stable_crate_id().to_u64(),
+ )
+}
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
new file mode 100644
index 000000000..cc9706f2d
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -0,0 +1,61 @@
+//! 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.
+
+use crate::ty::{self, TyCtxt};
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::LangItem;
+use rustc_span::Span;
+use rustc_target::spec::PanicStrategy;
+
+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` must 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 required(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.
+ match tcx.sess.panic_strategy() {
+ PanicStrategy::Abort => {
+ lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo
+ }
+ PanicStrategy::Unwind => true,
+ }
+}
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
new file mode 100644
index 000000000..acced0492
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -0,0 +1,85 @@
+//! Registering limits:
+//! * recursion_limit,
+//! * move_size_limit,
+//! * type_length_limit, and
+//! * const_eval_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::bug;
+use crate::ty;
+use rustc_ast::Attribute;
+use rustc_session::Session;
+use rustc_session::{Limit, Limits};
+use rustc_span::symbol::{sym, Symbol};
+
+use std::num::IntErrorKind;
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ providers.limits = |tcx, ()| Limits {
+ recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
+ move_size_limit: get_limit(
+ tcx.hir().krate_attrs(),
+ tcx.sess,
+ sym::move_size_limit,
+ tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0),
+ ),
+ type_length_limit: get_limit(
+ tcx.hir().krate_attrs(),
+ tcx.sess,
+ sym::type_length_limit,
+ 1048576,
+ ),
+ const_eval_limit: get_limit(
+ tcx.hir().krate_attrs(),
+ tcx.sess,
+ sym::const_eval_limit,
+ 1_000_000,
+ ),
+ }
+}
+
+pub fn get_recursion_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit {
+ get_limit(krate_attrs, sess, sym::recursion_limit, 128)
+}
+
+fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit {
+ for attr in krate_attrs {
+ if !attr.has_name(name) {
+ continue;
+ }
+
+ if let Some(s) = attr.value_str() {
+ match s.as_str().parse() {
+ Ok(n) => return Limit::new(n),
+ Err(e) => {
+ let mut err =
+ sess.struct_span_err(attr.span, "`limit` must be a non-negative integer");
+
+ let value_span = attr
+ .meta()
+ .and_then(|meta| meta.name_value_literal_span())
+ .unwrap_or(attr.span);
+
+ let error_str = match e.kind() {
+ IntErrorKind::PosOverflow => "`limit` is too large",
+ IntErrorKind::Empty => "`limit` must be a non-negative integer",
+ IntErrorKind::InvalidDigit => "not a valid integer",
+ IntErrorKind::NegOverflow => {
+ bug!("`limit` should never negatively overflow")
+ }
+ IntErrorKind::Zero => bug!("zero is a valid `limit`"),
+ kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
+ };
+
+ err.span_label(value_span, error_str);
+ err.emit();
+ }
+ }
+ }
+ }
+ return Limit::new(default);
+}
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
new file mode 100644
index 000000000..8dc68b1f5
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -0,0 +1,37 @@
+pub mod codegen_fn_attrs;
+pub mod dependency_format;
+pub mod exported_symbols;
+pub mod lang_items;
+pub mod lib_features {
+ use rustc_data_structures::fx::FxHashMap;
+ use rustc_span::{symbol::Symbol, Span};
+
+ #[derive(HashStable, Debug)]
+ pub struct LibFeatures {
+ /// A map from feature to stabilisation version.
+ pub stable: FxHashMap<Symbol, (Symbol, Span)>,
+ pub unstable: FxHashMap<Symbol, Span>,
+ }
+
+ 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(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap());
+ all_features
+ }
+ }
+}
+pub mod limits;
+pub mod privacy;
+pub mod region;
+pub mod resolve_lifetime;
+pub mod stability;
+
+pub fn provide(providers: &mut crate::ty::query::Providers) {
+ limits::provide(providers);
+}
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
new file mode 100644
index 000000000..751c7f464
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -0,0 +1,64 @@
+//! 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_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_macros::HashStable;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_span::def_id::LocalDefId;
+use std::hash::Hash;
+
+/// Represents the levels of accessibility an item can have.
+///
+/// The variants are sorted in ascending order of accessibility.
+#[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 the help of `pub use` re-exports.
+ Exported,
+ /// Items accessible to other crates directly, without the help of re-exports.
+ Public,
+}
+
+/// Holds a map of accessibility levels for reachable HIR nodes.
+#[derive(Debug, Clone)]
+pub struct AccessLevels<Id = LocalDefId> {
+ 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> Default for AccessLevels<Id> {
+ fn default() -> Self {
+ AccessLevels { map: Default::default() }
+ }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ let AccessLevels { ref map } = *self;
+ map.hash_stable(hcx, hasher);
+ }
+}
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
new file mode 100644
index 000000000..c886175c6
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -0,0 +1,443 @@
+//! 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 dev guide].
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
+
+use crate::ty::TyCtxt;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir as hir;
+use rustc_hir::Node;
+use rustc_macros::HashStable;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_span::{Span, DUMMY_SP};
+
+use std::fmt;
+use std::ops::Deref;
+
+/// 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, TyEncodable, TyDecodable)]
+#[derive(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::IfThen => write!(fmt, "IfThen({:?})", 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, TyEncodable, TyDecodable)]
+#[derive(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 of the condition and then block of an if expression
+ /// Used for variables introduced in an if-let expression.
+ IfThen,
+
+ /// 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 an 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) -> Option<hir::HirId> {
+ scope_tree
+ .root_body
+ .map(|hir_id| hir::HirId { owner: hir_id.owner, local_id: self.item_local_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 Some(hir_id) = self.hir_id(scope_tree) else {
+ 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 alluded 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.with_lo(stmt_span.lo());
+ }
+ }
+ }
+ span
+ }
+}
+
+pub type ScopeDepth = u32;
+
+/// The region scope tree encodes information about region relationships.
+#[derive(TyEncodable, TyDecodable, Default, Debug)]
+pub struct ScopeTree {
+ /// If not empty, this body is the root of this region hierarchy.
+ pub root_body: 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: FxIndexMap<Scope, (Scope, ScopeDepth)>,
+
+ /// Maps from a variable or binding ID to the block in which that
+ /// variable is declared.
+ var_map: FxIndexMap<hir::ItemLocalId, Scope>,
+
+ /// Maps from a `NodeId` to the associated destruction scope (if any).
+ destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
+
+ /// Identifies expressions which, if captured into a temporary, ought to
+ /// have a temporary whose lifetime extends to the end of the enclosing *block*,
+ /// and not the enclosing *statement*. Expressions that are not present in this
+ /// table are not rvalue candidates. The set of rvalue candidates is computed
+ /// during type check based on a traversal of the AST.
+ pub rvalue_candidates: FxHashMap<hir::HirId, RvalueCandidateType>,
+
+ /// 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)
+ ///
+ /// ```text
+ /// 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)`. Suppose, as in our example,
+ /// U is the yield and D is 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, Vec<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>,
+}
+
+/// Identifies the reason that a given expression is an rvalue candidate
+/// (see the `rvalue_candidates` field for more information what rvalue
+/// candidates in general). In constants, the `lifetime` field is None
+/// to indicate that certain expressions escape into 'static and
+/// should have no local cleanup scope.
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub enum RvalueCandidateType {
+ Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
+ Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
+}
+
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, 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 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 opt_destruction_scope(&self, n: hir::ItemLocalId) -> Option<Scope> {
+ self.destruction_scopes.get(&n).cloned()
+ }
+
+ 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_candidate(
+ &mut self,
+ var: hir::HirId,
+ candidate_type: RvalueCandidateType,
+ ) {
+ debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})");
+ match &candidate_type {
+ RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. }
+ | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => {
+ assert!(var.local_id != lifetime.item_local_id())
+ }
+ _ => {}
+ }
+ self.rvalue_candidates.insert(var, candidate_type);
+ }
+
+ /// 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 lifetime of the local variable `var_id`, if any.
+ pub fn var_scope(&self, var_id: hir::ItemLocalId) -> Option<Scope> {
+ self.var_map.get(&var_id).cloned()
+ }
+
+ /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
+ /// `false` otherwise.
+ ///
+ /// Used by clippy.
+ 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);
+
+ true
+ }
+
+ /// Checks whether the given scope contains a `yield`. If so,
+ /// returns `Some(YieldData)`. If not, returns `None`.
+ pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> {
+ self.yield_in_scope.get(&scope).map(Deref::deref)
+ }
+
+ /// 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).copied()
+ }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ let ScopeTree {
+ root_body,
+ ref body_expr_count,
+ ref parent_map,
+ ref var_map,
+ ref destruction_scopes,
+ ref rvalue_candidates,
+ ref yield_in_scope,
+ } = *self;
+
+ root_body.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_candidates.hash_stable(hcx, hasher);
+ yield_in_scope.hash_stable(hcx, hasher);
+ }
+}
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
new file mode 100644
index 000000000..9b2f44567
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -0,0 +1,54 @@
+//! 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::ItemLocalId;
+use rustc_macros::HashStable;
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
+pub enum Region {
+ Static,
+ EarlyBound(/* index */ u32, /* lifetime decl */ DefId),
+ LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
+ 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, TyEncodable, TyDecodable, 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, Debug)]
+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<LocalDefId>>,
+
+ pub late_bound_vars: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
+}
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
new file mode 100644
index 000000000..414912dd0
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -0,0 +1,591 @@
+//! 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::ty::{self, DefIdTree, TyCtxt};
+use rustc_ast::NodeId;
+use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_feature::GateIssue;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{self as hir, HirId};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
+use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer};
+use rustc_session::parse::feature_err_issue;
+use rustc_session::Session;
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
+use std::num::NonZeroU32;
+
+#[derive(PartialEq, Clone, Copy, Debug)]
+pub enum StabilityLevel {
+ Unstable,
+ Stable,
+}
+
+/// An entry in the `depr_map`.
+#[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)]
+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<LocalDefId>,
+}
+
+impl DeprecationEntry {
+ pub fn local(attr: Deprecation, def_id: LocalDefId) -> DeprecationEntry {
+ DeprecationEntry { attr, origin: Some(def_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, Debug)]
+pub struct Index {
+ /// This is mostly a cache, except the stabilities of local items
+ /// are filled by the annotator.
+ pub stab_map: FxHashMap<LocalDefId, Stability>,
+ pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
+ pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
+ /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
+ /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
+ /// exists, then this map will have a `impliee -> implier` entry.
+ ///
+ /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
+ /// specify their implications (both `implies` and `implied_by`). If only one of the two
+ /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
+ /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
+ /// reported, only the `#[stable]` attribute information is available, so the map is necessary
+ /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
+ /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
+ /// unstable feature" error for a feature that was implied.
+ pub implications: FxHashMap<Symbol, Symbol>,
+}
+
+impl Index {
+ pub fn local_stability(&self, def_id: LocalDefId) -> Option<Stability> {
+ self.stab_map.get(&def_id).copied()
+ }
+
+ pub fn local_const_stability(&self, def_id: LocalDefId) -> Option<ConstStability> {
+ self.const_stab_map.get(&def_id).copied()
+ }
+
+ pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
+ self.depr_map.get(&def_id).cloned()
+ }
+}
+
+pub fn report_unstable(
+ sess: &Session,
+ feature: Symbol,
+ reason: Option<Symbol>,
+ issue: Option<NonZeroU32>,
+ suggestion: Option<(Span, String, String, Applicability)>,
+ 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),
+ };
+
+ if is_soft {
+ soft_handler(SOFT_UNSTABLE, span, &msg)
+ } else {
+ let mut err =
+ feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg);
+ if let Some((inner_types, ref msg, sugg, applicability)) = suggestion {
+ err.span_suggestion(inner_types, msg, sugg, applicability);
+ }
+ err.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(depr: &Deprecation) -> bool {
+ let is_since_rustc_version = depr.is_since_rustc_version;
+ let since = depr.since.as_ref().map(Symbol::as_str);
+
+ 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 !is_since_rustc_version {
+ // The `since` field doesn't have semantic purpose without `#![staged_api]`.
+ return true;
+ }
+
+ if let Some(since) = since {
+ if since == "TBD" {
+ return false;
+ }
+
+ 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;
+ }
+ return since <= rustc;
+ }
+ };
+
+ // Assume deprecation is in effect if "since" field is missing
+ // or if we can't determine the current Rust version.
+ true
+}
+
+pub fn deprecation_suggestion(
+ diag: &mut Diagnostic,
+ kind: &str,
+ suggestion: Option<Symbol>,
+ span: Span,
+) {
+ if let Some(suggestion) = suggestion {
+ diag.span_suggestion_verbose(
+ span,
+ &format!("replace the use of the deprecated {}", kind),
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+ }
+}
+
+fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
+ if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE }
+}
+
+fn deprecation_message(
+ is_in_effect: bool,
+ since: Option<Symbol>,
+ note: Option<Symbol>,
+ kind: &str,
+ path: &str,
+) -> String {
+ let message = if is_in_effect {
+ format!("use of deprecated {} `{}`", kind, path)
+ } else {
+ let since = since.as_ref().map(Symbol::as_str);
+
+ if since == Some("TBD") {
+ format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path)
+ } else {
+ format!(
+ "use of {} `{}` that will be deprecated in future version {}",
+ kind,
+ path,
+ since.unwrap()
+ )
+ }
+ };
+
+ match note {
+ Some(reason) => format!("{}: {}", message, reason),
+ None => message,
+ }
+}
+
+pub fn deprecation_message_and_lint(
+ depr: &Deprecation,
+ kind: &str,
+ path: &str,
+) -> (String, &'static Lint) {
+ let is_in_effect = deprecation_in_effect(depr);
+ (
+ deprecation_message(is_in_effect, depr.since, depr.note, kind, path),
+ deprecation_lint(is_in_effect),
+ )
+}
+
+pub fn early_report_deprecation<'a>(
+ lint_buffer: &'a mut LintBuffer,
+ message: &str,
+ suggestion: Option<Symbol>,
+ lint: &'static Lint,
+ span: Span,
+ node_id: NodeId,
+) {
+ if span.in_derive_expansion() {
+ return;
+ }
+
+ let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span);
+ lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag);
+}
+
+fn late_report_deprecation(
+ tcx: TyCtxt<'_>,
+ message: &str,
+ suggestion: Option<Symbol>,
+ lint: &'static Lint,
+ span: Span,
+ method_span: Option<Span>,
+ hir_id: HirId,
+ def_id: DefId,
+) {
+ if span.in_derive_expansion() {
+ return;
+ }
+ let method_span = method_span.unwrap_or(span);
+ tcx.struct_span_lint_hir(lint, hir_id, method_span, |lint| {
+ let mut diag = lint.build(message);
+ if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
+ let kind = tcx.def_kind(def_id).descr(def_id);
+ deprecation_suggestion(&mut diag, kind, suggestion, method_span);
+ }
+ diag.emit();
+ });
+}
+
+/// 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>,
+ suggestion: Option<(Span, String, String, Applicability)>,
+ 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<'_>, def_id: DefId) -> bool {
+ if tcx.def_kind(def_id) == DefKind::TyParam {
+ // Have no visibility, considered public for the purpose of this check.
+ return false;
+ }
+ match tcx.visibility(def_id) {
+ // 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,
+ }
+}
+
+// See issue #83250.
+fn suggestion_for_allocator_api(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+ span: Span,
+ feature: Symbol,
+) -> Option<(Span, String, String, Applicability)> {
+ if feature == sym::allocator_api {
+ if let Some(trait_) = tcx.opt_parent(def_id) {
+ if tcx.is_diagnostic_item(sym::Vec, trait_) {
+ let sm = tcx.sess.parse_sess.source_map();
+ let inner_types = sm.span_extend_to_prev_char(span, '<', true);
+ if let Ok(snippet) = sm.span_to_snippet(inner_types) {
+ return Some((
+ inner_types,
+ "consider wrapping the inner types in tuple".to_string(),
+ format!("({})", snippet),
+ Applicability::MaybeIncorrect,
+ ));
+ }
+ }
+ }
+ }
+ None
+}
+
+/// An override option for eval_stability.
+pub enum AllowUnstable {
+ /// Don't emit an unstable error for the item
+ Yes,
+ /// Handle the item normally
+ No,
+}
+
+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,
+ method_span: Option<Span>,
+ ) -> EvalResult {
+ self.eval_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
+ }
+
+ /// 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`.
+ ///
+ /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
+ pub fn eval_stability_allow_unstable(
+ self,
+ def_id: DefId,
+ id: Option<HirId>,
+ span: Span,
+ method_span: Option<Span>,
+ allow_unstable: AllowUnstable,
+ ) -> 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().get_parent_item(id);
+ let skip = self
+ .lookup_deprecation_entry(parent_def_id.to_def_id())
+ .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
+
+ // #[deprecated] doesn't emit a notice if we're not on the
+ // topmost deprecation. For example, if a struct is deprecated,
+ // the use of a field won't be linted.
+ //
+ // With #![staged_api], we want to emit down the whole
+ // hierarchy.
+ let depr_attr = &depr_entry.attr;
+ if !skip || depr_attr.is_since_rustc_version {
+ // Calculating message for lint involves calling `self.def_path_str`.
+ // Which by default to calculate visible path will invoke expensive `visible_parent_map` query.
+ // So we skip message calculation altogether, if lint is allowed.
+ let is_in_effect = deprecation_in_effect(depr_attr);
+ let lint = deprecation_lint(is_in_effect);
+ if self.lint_level_at_node(lint, id).0 != Level::Allow {
+ let def_path = with_no_trimmed_paths!(self.def_path_str(def_id));
+ let def_kind = self.def_kind(def_id).descr(def_id);
+
+ late_report_deprecation(
+ self,
+ &deprecation_message(
+ is_in_effect,
+ depr_attr.since,
+ depr_attr.note,
+ def_kind,
+ &def_path,
+ ),
+ depr_attr.suggestion,
+ lint,
+ span,
+ method_span,
+ id,
+ def_id,
+ );
+ }
+ }
+ };
+ }
+
+ let is_staged_api = self.lookup_stability(def_id.krate.as_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
+ );
+
+ // 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, implied_by },
+ feature,
+ ..
+ }) => {
+ if span.allows_unstable(feature) {
+ debug!("stability: skipping span={:?} since it is internal", span);
+ return EvalResult::Allow;
+ }
+ if self.features().active(feature) {
+ return EvalResult::Allow;
+ }
+
+ // If this item was previously part of a now-stabilized feature which is still
+ // active (i.e. the user hasn't removed the attribute for the stabilized feature
+ // yet) then allow use of this item.
+ if let Some(implied_by) = implied_by && self.features().active(implied_by) {
+ 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.unstable_opts.force_unstable_if_unmarked {
+ return EvalResult::Allow;
+ }
+ }
+
+ if matches!(allow_unstable, AllowUnstable::Yes) {
+ return EvalResult::Allow;
+ }
+
+ let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
+ EvalResult::Deny {
+ feature,
+ reason: reason.to_opt_reason(),
+ issue,
+ suggestion,
+ 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.
+ ///
+ /// 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.
+ ///
+ /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
+ pub fn check_stability(
+ self,
+ def_id: DefId,
+ id: Option<HirId>,
+ span: Span,
+ method_span: Option<Span>,
+ ) -> bool {
+ self.check_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
+ }
+
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
+ ///
+ /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
+ pub fn check_stability_allow_unstable(
+ self,
+ def_id: DefId,
+ id: Option<HirId>,
+ span: Span,
+ method_span: Option<Span>,
+ allow_unstable: AllowUnstable,
+ ) -> bool {
+ self.check_optional_stability(
+ def_id,
+ id,
+ span,
+ method_span,
+ allow_unstable,
+ |span, def_id| {
+ // 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));
+ },
+ )
+ }
+
+ /// Like `check_stability`, except that we permit items to have custom behaviour for
+ /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary
+ /// for default generic parameters, which only have stability attributes if they were
+ /// added after the type on which they're defined.
+ ///
+ /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
+ pub fn check_optional_stability(
+ self,
+ def_id: DefId,
+ id: Option<HirId>,
+ span: Span,
+ method_span: Option<Span>,
+ allow_unstable: AllowUnstable,
+ unmarked: impl FnOnce(Span, DefId),
+ ) -> bool {
+ 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();
+ })
+ };
+ let eval_result =
+ self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);
+ let is_allowed = matches!(eval_result, EvalResult::Allow);
+ match eval_result {
+ EvalResult::Allow => {}
+ EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
+ self.sess,
+ feature,
+ reason,
+ issue,
+ suggestion,
+ is_soft,
+ span,
+ soft_handler,
+ ),
+ EvalResult::Unmarked => unmarked(span, def_id),
+ }
+
+ is_allowed
+ }
+
+ pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
+ self.lookup_deprecation_entry(id).map(|depr| depr.attr)
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
new file mode 100644
index 000000000..78080fcd5
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -0,0 +1,147 @@
+use crate::mir::graph_cyclic_cache::GraphIsCyclicCache;
+use crate::mir::predecessors::{PredecessorCache, Predecessors};
+use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources};
+use crate::mir::traversal::PostorderCache;
+use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK};
+
+use rustc_data_structures::graph;
+use rustc_data_structures::graph::dominators::{dominators, Dominators};
+use rustc_index::vec::IndexVec;
+
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
+pub struct BasicBlocks<'tcx> {
+ basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+ predecessor_cache: PredecessorCache,
+ switch_source_cache: SwitchSourceCache,
+ is_cyclic: GraphIsCyclicCache,
+ postorder_cache: PostorderCache,
+}
+
+impl<'tcx> BasicBlocks<'tcx> {
+ #[inline]
+ pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
+ BasicBlocks {
+ basic_blocks,
+ predecessor_cache: PredecessorCache::new(),
+ switch_source_cache: SwitchSourceCache::new(),
+ is_cyclic: GraphIsCyclicCache::new(),
+ postorder_cache: PostorderCache::new(),
+ }
+ }
+
+ /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
+ #[inline]
+ pub fn is_cfg_cyclic(&self) -> bool {
+ self.is_cyclic.is_cyclic(self)
+ }
+
+ #[inline]
+ pub fn dominators(&self) -> Dominators<BasicBlock> {
+ dominators(&self)
+ }
+
+ /// Returns predecessors for each basic block.
+ #[inline]
+ pub fn predecessors(&self) -> &Predecessors {
+ self.predecessor_cache.compute(&self.basic_blocks)
+ }
+
+ /// Returns basic blocks in a postorder.
+ #[inline]
+ pub fn postorder(&self) -> &[BasicBlock] {
+ self.postorder_cache.compute(&self.basic_blocks)
+ }
+
+ /// `switch_sources()[&(target, switch)]` returns a list of switch
+ /// values that lead to a `target` block from a `switch` block.
+ #[inline]
+ pub fn switch_sources(&self) -> &SwitchSources {
+ self.switch_source_cache.compute(&self.basic_blocks)
+ }
+
+ /// Returns mutable reference to basic blocks. Invalidates CFG cache.
+ #[inline]
+ pub fn as_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+ self.invalidate_cfg_cache();
+ &mut self.basic_blocks
+ }
+
+ /// Get mutable access to basic blocks without invalidating the CFG cache.
+ ///
+ /// By calling this method instead of e.g. [`BasicBlocks::as_mut`] you promise not to change
+ /// the CFG. This means that
+ ///
+ /// 1) The number of basic blocks remains unchanged
+ /// 2) The set of successors of each terminator remains unchanged.
+ /// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
+ /// kind is not changed.
+ ///
+ /// If any of these conditions cannot be upheld, you should call [`BasicBlocks::invalidate_cfg_cache`].
+ #[inline]
+ pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+ &mut self.basic_blocks
+ }
+
+ /// Invalidates cached information about the CFG.
+ ///
+ /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`].
+ /// All other methods that allow you to mutate the basic blocks also call this method
+ /// themselves, thereby avoiding any risk of accidentaly cache invalidation.
+ pub fn invalidate_cfg_cache(&mut self) {
+ self.predecessor_cache.invalidate();
+ self.switch_source_cache.invalidate();
+ self.is_cyclic.invalidate();
+ self.postorder_cache.invalidate();
+ }
+}
+
+impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> {
+ type Target = IndexVec<BasicBlock, BasicBlockData<'tcx>>;
+
+ #[inline]
+ fn deref(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+ &self.basic_blocks
+ }
+}
+
+impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
+ type Node = BasicBlock;
+}
+
+impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> {
+ #[inline]
+ fn num_nodes(&self) -> usize {
+ self.basic_blocks.len()
+ }
+}
+
+impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
+ #[inline]
+ fn start_node(&self) -> Self::Node {
+ START_BLOCK
+ }
+}
+
+impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> {
+ #[inline]
+ fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
+ self.basic_blocks[node].terminator().successors()
+ }
+}
+
+impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> {
+ type Item = BasicBlock;
+ type Iter = Successors<'b>;
+}
+
+impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
+ type Item = BasicBlock;
+ type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
+}
+
+impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
+ #[inline]
+ fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
+ self.predecessors()[node].iter().copied()
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
new file mode 100644
index 000000000..efa946452
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -0,0 +1,186 @@
+//! Metadata from source code coverage analysis and instrumentation.
+
+use rustc_macros::HashStable;
+use rustc_span::Symbol;
+
+use std::cmp::Ord;
+use std::fmt::{self, Debug, Formatter};
+
+rustc_index::newtype_index! {
+ /// An ExpressionOperandId value is assigned directly from either a
+ /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32()
+ /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a
+ /// constant value of `0`.
+ pub struct ExpressionOperandId {
+ derive [HashStable]
+ DEBUG_FORMAT = "ExpressionOperandId({})",
+ MAX = 0xFFFF_FFFF,
+ }
+}
+
+impl ExpressionOperandId {
+ /// An expression operand for a "zero counter", as described in the following references:
+ ///
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
+ ///
+ /// This operand can be used to count two or more separate code regions with a single counter,
+ /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
+ /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
+ /// the coverage map for the other code regions.
+ pub const ZERO: Self = Self::from_u32(0);
+}
+
+rustc_index::newtype_index! {
+ pub struct CounterValueReference {
+ derive [HashStable]
+ DEBUG_FORMAT = "CounterValueReference({})",
+ MAX = 0xFFFF_FFFF,
+ }
+}
+
+impl CounterValueReference {
+ /// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
+ pub const START: Self = Self::from_u32(1);
+
+ /// Returns explicitly-requested zero-based version of the counter id, used
+ /// during codegen. LLVM expects zero-based indexes.
+ pub fn zero_based_index(self) -> u32 {
+ let one_based_index = self.as_u32();
+ debug_assert!(one_based_index > 0);
+ one_based_index - 1
+ }
+}
+
+rustc_index::newtype_index! {
+ /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
+ ///
+ /// Values descend from u32::MAX.
+ pub struct InjectedExpressionId {
+ derive [HashStable]
+ DEBUG_FORMAT = "InjectedExpressionId({})",
+ MAX = 0xFFFF_FFFF,
+ }
+}
+
+rustc_index::newtype_index! {
+ /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
+ ///
+ /// Values ascend from 0.
+ pub struct InjectedExpressionIndex {
+ derive [HashStable]
+ DEBUG_FORMAT = "InjectedExpressionIndex({})",
+ MAX = 0xFFFF_FFFF,
+ }
+}
+
+rustc_index::newtype_index! {
+ /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
+ /// array position in the LLVM coverage map "Expressions" array, which is assembled during the
+ /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
+ pub struct MappedExpressionIndex {
+ derive [HashStable]
+ DEBUG_FORMAT = "MappedExpressionIndex({})",
+ MAX = 0xFFFF_FFFF,
+ }
+}
+
+impl From<CounterValueReference> for ExpressionOperandId {
+ #[inline]
+ fn from(v: CounterValueReference) -> ExpressionOperandId {
+ ExpressionOperandId::from(v.as_u32())
+ }
+}
+
+impl From<InjectedExpressionId> for ExpressionOperandId {
+ #[inline]
+ fn from(v: InjectedExpressionId) -> ExpressionOperandId {
+ ExpressionOperandId::from(v.as_u32())
+ }
+}
+
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub enum CoverageKind {
+ Counter {
+ function_source_hash: u64,
+ id: CounterValueReference,
+ },
+ Expression {
+ id: InjectedExpressionId,
+ lhs: ExpressionOperandId,
+ op: Op,
+ rhs: ExpressionOperandId,
+ },
+ Unreachable,
+}
+
+impl CoverageKind {
+ pub fn as_operand_id(&self) -> ExpressionOperandId {
+ use CoverageKind::*;
+ match *self {
+ Counter { id, .. } => ExpressionOperandId::from(id),
+ Expression { id, .. } => ExpressionOperandId::from(id),
+ Unreachable => bug!("Unreachable coverage cannot be part of an expression"),
+ }
+ }
+
+ pub fn is_expression(&self) -> bool {
+ matches!(self, Self::Expression { .. })
+ }
+}
+
+impl Debug for CoverageKind {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ use CoverageKind::*;
+ match self {
+ Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
+ Expression { id, lhs, op, rhs } => write!(
+ fmt,
+ "Expression({:?}) = {} {} {}",
+ id.index(),
+ lhs.index(),
+ if *op == Op::Add { "+" } else { "-" },
+ rhs.index(),
+ ),
+ Unreachable => write!(fmt, "Unreachable"),
+ }
+ }
+}
+
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct CodeRegion {
+ pub file_name: Symbol,
+ pub start_line: u32,
+ pub start_col: u32,
+ pub end_line: u32,
+ pub end_col: u32,
+}
+
+impl Debug for CodeRegion {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ write!(
+ fmt,
+ "{}:{}:{} - {}:{}",
+ self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
+ )
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum Op {
+ Subtract,
+ Add,
+}
+
+impl Op {
+ pub fn is_add(&self) -> bool {
+ matches!(self, Self::Add)
+ }
+
+ pub fn is_subtract(&self) -> bool {
+ matches!(self, Self::Subtract)
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs
new file mode 100644
index 000000000..f3621cd99
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/generic_graph.rs
@@ -0,0 +1,69 @@
+use gsgdt::{Edge, Graph, Node, NodeStyle};
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+/// Convert an MIR function into a gsgdt Graph
+pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph {
+ let def_id = body.source.def_id();
+ let def_name = graphviz_safe_def_name(def_id);
+ let graph_name = format!("Mir_{}", def_name);
+ let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
+
+ // Nodes
+ let nodes: Vec<Node> = body
+ .basic_blocks()
+ .iter_enumerated()
+ .map(|(block, _)| bb_to_graph_node(block, body, dark_mode))
+ .collect();
+
+ // Edges
+ let mut edges = Vec::new();
+ for (source, _) in body.basic_blocks().iter_enumerated() {
+ let def_id = body.source.def_id();
+ let terminator = body[source].terminator();
+ let labels = terminator.kind.fmt_successor_labels();
+
+ for (target, label) in terminator.successors().zip(labels) {
+ let src = node(def_id, source);
+ let trg = node(def_id, target);
+ edges.push(Edge::new(src, trg, label.to_string()));
+ }
+ }
+
+ Graph::new(graph_name, nodes, edges)
+}
+
+fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node {
+ let def_id = body.source.def_id();
+ let data = &body[block];
+ let label = node(def_id, block);
+
+ let (title, bgcolor) = if data.is_cleanup {
+ let color = if dark_mode { "royalblue" } else { "lightblue" };
+ (format!("{} (cleanup)", block.index()), color)
+ } else {
+ let color = if dark_mode { "dimgray" } else { "gray" };
+ (format!("{}", block.index()), color)
+ };
+
+ let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() };
+ let mut stmts: Vec<String> = data.statements.iter().map(|x| format!("{:?}", x)).collect();
+
+ // add the terminator to the stmts, gsgdt can print it out separately
+ let mut terminator_head = String::new();
+ data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
+ stmts.push(terminator_head);
+
+ Node::new(stmts, label, title, style)
+}
+
+// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
+// it does not have to be user friendly.
+pub fn graphviz_safe_def_name(def_id: DefId) -> String {
+ format!("{}_{}", def_id.krate.index(), def_id.index.index(),)
+}
+
+fn node(def_id: DefId, block: BasicBlock) -> String {
+ format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
+}
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
new file mode 100644
index 000000000..11ac45943
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -0,0 +1,173 @@
+use rustc_data_structures::graph::{self, iterate};
+use rustc_graphviz as dot;
+use rustc_middle::ty::TyCtxt;
+use std::io::{self, Write};
+
+pub struct GraphvizWriter<
+ 'a,
+ G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
+ NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+ EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+> {
+ graph: &'a G,
+ is_subgraph: bool,
+ graphviz_name: String,
+ graph_label: Option<String>,
+ node_content_fn: NodeContentFn,
+ edge_labels_fn: EdgeLabelsFn,
+}
+
+impl<
+ 'a,
+ G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
+ NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+ EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+> GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
+{
+ pub fn new(
+ graph: &'a G,
+ graphviz_name: &str,
+ node_content_fn: NodeContentFn,
+ edge_labels_fn: EdgeLabelsFn,
+ ) -> Self {
+ Self {
+ graph,
+ is_subgraph: false,
+ graphviz_name: graphviz_name.to_owned(),
+ graph_label: None,
+ node_content_fn,
+ edge_labels_fn,
+ }
+ }
+
+ pub fn set_graph_label(&mut self, graph_label: &str) {
+ self.graph_label = Some(graph_label.to_owned());
+ }
+
+ /// Write a graphviz DOT of the graph
+ pub fn write_graphviz<'tcx, W>(&self, tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()>
+ where
+ W: Write,
+ {
+ let kind = if self.is_subgraph { "subgraph" } else { "digraph" };
+ let cluster = if self.is_subgraph { "cluster_" } else { "" }; // Print border around graph
+ // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation,
+ // prepend "Mir_" to the graphviz_safe_def_name(def_id)
+ writeln!(w, "{} {}{} {{", kind, cluster, self.graphviz_name)?;
+
+ // Global graph properties
+ let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font);
+ let mut graph_attrs = vec![&font[..]];
+ let mut content_attrs = vec![&font[..]];
+
+ let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
+ if dark_mode {
+ graph_attrs.push(r#"bgcolor="black""#);
+ graph_attrs.push(r#"fontcolor="white""#);
+ content_attrs.push(r#"color="white""#);
+ content_attrs.push(r#"fontcolor="white""#);
+ }
+
+ writeln!(w, r#" graph [{}];"#, graph_attrs.join(" "))?;
+ let content_attrs_str = content_attrs.join(" ");
+ writeln!(w, r#" node [{}];"#, content_attrs_str)?;
+ writeln!(w, r#" edge [{}];"#, content_attrs_str)?;
+
+ // Graph label
+ if let Some(graph_label) = &self.graph_label {
+ self.write_graph_label(graph_label, w)?;
+ }
+
+ // Nodes
+ for node in iterate::post_order_from(self.graph, self.graph.start_node()) {
+ self.write_node(node, dark_mode, w)?;
+ }
+
+ // Edges
+ for source in iterate::post_order_from(self.graph, self.graph.start_node()) {
+ self.write_edges(source, w)?;
+ }
+ writeln!(w, "}}")
+ }
+
+ /// Write a graphviz DOT node for the given node.
+ pub fn write_node<W>(&self, node: G::Node, dark_mode: bool, w: &mut W) -> io::Result<()>
+ where
+ W: Write,
+ {
+ // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
+ write!(w, r#" {} [shape="none", label=<"#, self.node(node))?;
+
+ write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#)?;
+
+ // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation,
+ // we need generic way to know if node header should have a different color. For example,
+ // for MIR:
+ //
+ // let (blk, bgcolor) = if data.is_cleanup {
+ // let color = if dark_mode { "royalblue" } else { "lightblue" };
+ // (format!("{:?} (cleanup)", node), color)
+ // } else {
+ // let color = if dark_mode { "dimgray" } else { "gray" };
+ // (format!("{:?}", node), color)
+ // };
+ let color = if dark_mode { "dimgray" } else { "gray" };
+ let (blk, bgcolor) = (format!("{:?}", node), color);
+ write!(
+ w,
+ r#"<tr><td bgcolor="{bgcolor}" {attrs} colspan="{colspan}">{blk}</td></tr>"#,
+ attrs = r#"align="center""#,
+ colspan = 1,
+ blk = blk,
+ bgcolor = bgcolor
+ )?;
+
+ for section in (self.node_content_fn)(node) {
+ write!(
+ w,
+ r#"<tr><td align="left" balign="left">{}</td></tr>"#,
+ dot::escape_html(&section).replace('\n', "<br/>")
+ )?;
+ }
+
+ // Close the table
+ write!(w, "</table>")?;
+
+ // Close the node label and the node itself.
+ writeln!(w, ">];")
+ }
+
+ /// Write graphviz DOT edges with labels between the given node and all of its successors.
+ fn write_edges<W>(&self, source: G::Node, w: &mut W) -> io::Result<()>
+ where
+ W: Write,
+ {
+ let edge_labels = (self.edge_labels_fn)(source);
+ for (index, target) in self.graph.successors(source).enumerate() {
+ let src = self.node(source);
+ let trg = self.node(target);
+ let escaped_edge_label = if let Some(edge_label) = edge_labels.get(index) {
+ dot::escape_html(edge_label).replace('\n', r#"<br align="left"/>"#)
+ } else {
+ "".to_owned()
+ };
+ writeln!(w, r#" {} -> {} [label=<{}>];"#, src, trg, escaped_edge_label)?;
+ }
+ Ok(())
+ }
+
+ /// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
+ /// will appear below the graph.
+ fn write_graph_label<W>(&self, label: &str, w: &mut W) -> io::Result<()>
+ where
+ W: Write,
+ {
+ let lines = label.split('\n').map(|s| dot::escape_html(s)).collect::<Vec<_>>();
+ let escaped_label = lines.join(r#"<br align="left"/>"#);
+ writeln!(w, r#" label=<<br/><br/>{}<br align="left"/><br/><br/><br/>>;"#, escaped_label)
+ }
+
+ fn node(&self, node: G::Node) -> String {
+ format!("{:?}__{}", node, self.graphviz_name)
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
new file mode 100644
index 000000000..f97bf2883
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
@@ -0,0 +1,63 @@
+use rustc_data_structures::graph::{
+ self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors,
+};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+/// Helper type to cache the result of `graph::is_cyclic`.
+#[derive(Clone, Debug)]
+pub(super) struct GraphIsCyclicCache {
+ cache: OnceCell<bool>,
+}
+
+impl GraphIsCyclicCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ GraphIsCyclicCache { cache: OnceCell::new() }
+ }
+
+ pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool
+ where
+ G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
+ {
+ *self.cache.get_or_init(|| graph::is_cyclic(graph))
+ }
+
+ /// Invalidates the cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ // Invalidating the cache requires mutating the MIR, which in turn requires a unique
+ // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
+ // callers of `invalidate` have a unique reference to the MIR and thus to the
+ // cache. This means we never need to do synchronization when `invalidate` is called,
+ // we can simply reinitialize the `OnceCell`.
+ self.cache = OnceCell::new();
+ }
+}
+
+impl<S: Encoder> Encodable<S> for GraphIsCyclicCache {
+ #[inline]
+ fn encode(&self, s: &mut S) {
+ Encodable::encode(&(), s);
+ }
+}
+
+impl<D: Decoder> Decodable<D> for GraphIsCyclicCache {
+ #[inline]
+ fn decode(d: &mut D) -> Self {
+ let () = Decodable::decode(d);
+ Self::new()
+ }
+}
+
+impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ GraphIsCyclicCache,
+}
diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
new file mode 100644
index 000000000..5de56dad0
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/graphviz.rs
@@ -0,0 +1,134 @@
+use gsgdt::GraphvizSettings;
+use rustc_graphviz as dot;
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, TyCtxt};
+use std::fmt::Debug;
+use std::io::{self, Write};
+
+use super::generic_graph::mir_fn_to_generic_graph;
+use super::pretty::dump_mir_def_ids;
+
+/// Write a graphviz DOT graph of a list of MIRs.
+pub fn write_mir_graphviz<W>(tcx: TyCtxt<'_>, single: Option<DefId>, w: &mut W) -> io::Result<()>
+where
+ W: Write,
+{
+ let def_ids = dump_mir_def_ids(tcx, single);
+
+ let mirs =
+ def_ids
+ .iter()
+ .flat_map(|def_id| {
+ if tcx.is_const_fn_raw(*def_id) {
+ vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
+ } else {
+ vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
+ *def_id,
+ )))]
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let use_subgraphs = mirs.len() > 1;
+ if use_subgraphs {
+ writeln!(w, "digraph __crate__ {{")?;
+ }
+
+ for mir in mirs {
+ write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?;
+ }
+
+ if use_subgraphs {
+ writeln!(w, "}}")?;
+ }
+
+ Ok(())
+}
+
+/// Write a graphviz DOT graph of the MIR.
+pub fn write_mir_fn_graphviz<'tcx, W>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'_>,
+ subgraph: bool,
+ w: &mut W,
+) -> io::Result<()>
+where
+ W: Write,
+{
+ // Global graph properties
+ let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font);
+ let mut graph_attrs = vec![&font[..]];
+ let mut content_attrs = vec![&font[..]];
+
+ let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode;
+ if dark_mode {
+ graph_attrs.push(r#"bgcolor="black""#);
+ graph_attrs.push(r#"fontcolor="white""#);
+ content_attrs.push(r#"color="white""#);
+ content_attrs.push(r#"fontcolor="white""#);
+ }
+
+ // Graph label
+ let mut label = String::from("");
+ // FIXME: remove this unwrap
+ write_graph_label(tcx, body, &mut label).unwrap();
+ let g = mir_fn_to_generic_graph(tcx, body);
+ let settings = GraphvizSettings {
+ graph_attrs: Some(graph_attrs.join(" ")),
+ node_attrs: Some(content_attrs.join(" ")),
+ edge_attrs: Some(content_attrs.join(" ")),
+ graph_label: Some(label),
+ };
+ g.to_dot(w, &settings, subgraph)
+}
+
+/// Write the graphviz DOT label for the overall graph. This is essentially a block of text that
+/// will appear below the graph, showing the type of the `fn` this MIR represents and the types of
+/// all the variables and temporaries.
+fn write_graph_label<'tcx, W: std::fmt::Write>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'_>,
+ w: &mut W,
+) -> std::fmt::Result {
+ let def_id = body.source.def_id();
+
+ write!(w, "fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;
+
+ // fn argument types.
+ for (i, arg) in body.args_iter().enumerate() {
+ if i > 0 {
+ write!(w, ", ")?;
+ }
+ write!(w, "{:?}: {}", Place::from(arg), escape(&body.local_decls[arg].ty))?;
+ }
+
+ write!(w, ") -&gt; {}", escape(&body.return_ty()))?;
+ write!(w, r#"<br align="left"/>"#)?;
+
+ for local in body.vars_and_temps_iter() {
+ let decl = &body.local_decls[local];
+
+ write!(w, "let ")?;
+ if decl.mutability == Mutability::Mut {
+ write!(w, "mut ")?;
+ }
+
+ write!(w, r#"{:?}: {};<br align="left"/>"#, Place::from(local), escape(&decl.ty))?;
+ }
+
+ for var_debug_info in &body.var_debug_info {
+ write!(
+ w,
+ r#"debug {} =&gt; {};<br align="left"/>"#,
+ var_debug_info.name,
+ escape(&var_debug_info.value),
+ )?;
+ }
+
+ Ok(())
+}
+
+fn escape<T: Debug>(t: &T) -> String {
+ dot::escape_html(&format!("{:?}", t))
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
new file mode 100644
index 000000000..db7e0fb8a
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -0,0 +1,1300 @@
+//! The virtual memory representation of the MIR interpreter.
+
+use std::borrow::Cow;
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
+use std::hash;
+use std::iter;
+use std::ops::{Deref, Range};
+use std::ptr;
+
+use rustc_ast::Mutability;
+use rustc_data_structures::intern::Interned;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_span::DUMMY_SP;
+use rustc_target::abi::{Align, HasDataLayout, Size};
+
+use super::{
+ read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance,
+ ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, ScalarSizeMismatch, UndefinedBehaviorInfo,
+ UninitBytesAccess, UnsupportedOpInfo,
+};
+use crate::ty;
+
+/// This type represents an Allocation in the Miri/CTFE core engine.
+///
+/// Its public API is rather low-level, working directly with allocation offsets and a custom error
+/// type to account for the lack of an AllocId on this level. The Miri/CTFE core engine `memory`
+/// module provides higher-level access.
+// Note: for performance reasons when interning, some of the `Allocation` fields can be partially
+// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable)]
+pub struct Allocation<Prov = AllocId, Extra = ()> {
+ /// The actual bytes of the allocation.
+ /// Note that the bytes of a pointer represent the offset of the pointer.
+ bytes: Box<[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<Prov>,
+ /// Denotes which part of this allocation is initialized.
+ init_mask: InitMask,
+ /// The alignment of the allocation to detect unaligned reads.
+ /// (`Align` guarantees that this is a power of two.)
+ 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,
+}
+
+/// This is the maximum size we will hash at a time, when interning an `Allocation` and its
+/// `InitMask`. Note, we hash that amount of bytes twice: at the start, and at the end of a buffer.
+/// Used when these two structures are large: we only partially hash the larger fields in that
+/// situation. See the comment at the top of their respective `Hash` impl for more details.
+const MAX_BYTES_TO_HASH: usize = 64;
+
+/// This is the maximum size (in bytes) for which a buffer will be fully hashed, when interning.
+/// Otherwise, it will be partially hashed in 2 slices, requiring at least 2 `MAX_BYTES_TO_HASH`
+/// bytes.
+const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH;
+
+// Const allocations are only hashed for interning. However, they can be large, making the hashing
+// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
+// big buffers like the actual bytes of allocation. We can partially hash some fields when they're
+// large.
+impl hash::Hash for Allocation {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ // Partially hash the `bytes` buffer when it is large. To limit collisions with common
+ // prefixes and suffixes, we hash the length and some slices of the buffer.
+ let byte_count = self.bytes.len();
+ if byte_count > MAX_HASHED_BUFFER_LEN {
+ // Hash the buffer's length.
+ byte_count.hash(state);
+
+ // And its head and tail.
+ self.bytes[..MAX_BYTES_TO_HASH].hash(state);
+ self.bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state);
+ } else {
+ self.bytes.hash(state);
+ }
+
+ // Hash the other fields as usual.
+ self.relocations.hash(state);
+ self.init_mask.hash(state);
+ self.align.hash(state);
+ self.mutability.hash(state);
+ self.extra.hash(state);
+ }
+}
+
+/// Interned types generally have an `Outer` type and an `Inner` type, where
+/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
+/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
+/// outer type and `TyS` is its inner type.
+///
+/// Here things are different because only const allocations are interned. This
+/// means that both the inner type (`Allocation`) and the outer type
+/// (`ConstAllocation`) are used quite a bit.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[rustc_pass_by_value]
+pub struct ConstAllocation<'tcx, Prov = AllocId, Extra = ()>(
+ pub Interned<'tcx, Allocation<Prov, Extra>>,
+);
+
+impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This matches how `Allocation` is printed. We print it like this to
+ // avoid having to update expected output in a lot of tests.
+ write!(f, "{:?}", self.inner())
+ }
+}
+
+impl<'tcx, Prov, Extra> ConstAllocation<'tcx, Prov, Extra> {
+ pub fn inner(self) -> &'tcx Allocation<Prov, Extra> {
+ self.0.0
+ }
+}
+
+/// We have our own error type that does not know about the `AllocId`; that information
+/// is added when converting to `InterpError`.
+#[derive(Debug)]
+pub enum AllocError {
+ /// A scalar had the wrong size.
+ ScalarSizeMismatch(ScalarSizeMismatch),
+ /// Encountered a pointer where we needed raw bytes.
+ ReadPointerAsBytes,
+ /// Partially overwriting a pointer.
+ PartialPointerOverwrite(Size),
+ /// Using uninitialized data where it is not allowed.
+ InvalidUninitBytes(Option<UninitBytesAccess>),
+}
+pub type AllocResult<T = ()> = Result<T, AllocError>;
+
+impl From<ScalarSizeMismatch> for AllocError {
+ fn from(s: ScalarSizeMismatch) -> Self {
+ AllocError::ScalarSizeMismatch(s)
+ }
+}
+
+impl AllocError {
+ pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
+ use AllocError::*;
+ match self {
+ ScalarSizeMismatch(s) => {
+ InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
+ }
+ ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes),
+ PartialPointerOverwrite(offset) => InterpError::Unsupported(
+ UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)),
+ ),
+ InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
+ UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
+ ),
+ }
+ }
+}
+
+/// The information that makes up a memory access: offset and size.
+#[derive(Copy, Clone)]
+pub struct AllocRange {
+ pub start: Size,
+ pub size: Size,
+}
+
+impl fmt::Debug for AllocRange {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes())
+ }
+}
+
+/// Free-starting constructor for less syntactic overhead.
+#[inline(always)]
+pub fn alloc_range(start: Size, size: Size) -> AllocRange {
+ AllocRange { start, size }
+}
+
+impl AllocRange {
+ #[inline]
+ pub fn from(r: Range<Size>) -> Self {
+ alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
+ }
+
+ #[inline(always)]
+ pub fn end(self) -> Size {
+ self.start + self.size // This does overflow checking.
+ }
+
+ /// Returns the `subrange` within this range; panics if it is not a subrange.
+ #[inline]
+ pub fn subrange(self, subrange: AllocRange) -> AllocRange {
+ let sub_start = self.start + subrange.start;
+ let range = alloc_range(sub_start, subrange.size);
+ assert!(range.end() <= self.end(), "access outside the bounds for given AllocRange");
+ range
+ }
+}
+
+// The constructors are all without extra; the extra gets added by a machine hook later.
+impl<Prov> Allocation<Prov> {
+ /// Creates an allocation initialized by the given bytes
+ pub fn from_bytes<'a>(
+ slice: impl Into<Cow<'a, [u8]>>,
+ align: Align,
+ mutability: Mutability,
+ ) -> Self {
+ let bytes = Box::<[u8]>::from(slice.into());
+ let size = Size::from_bytes(bytes.len());
+ Self {
+ bytes,
+ relocations: Relocations::new(),
+ init_mask: InitMask::new(size, true),
+ align,
+ mutability,
+ extra: (),
+ }
+ }
+
+ pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
+ Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
+ }
+
+ /// Try to create an Allocation of `size` bytes, failing if there is not enough memory
+ /// available to the compiler to do so.
+ ///
+ /// If `panic_on_fail` is true, this will never return `Err`.
+ pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> {
+ let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| {
+ // This results in an error that can happen non-deterministically, since the memory
+ // available to the compiler can change between runs. Normally queries are always
+ // deterministic. However, we can be non-deterministic here because all uses of const
+ // evaluation (including ConstProp!) will make compilation fail (via hard error
+ // or ICE) upon encountering a `MemoryExhausted` error.
+ if panic_on_fail {
+ panic!("Allocation::uninit called with panic_on_fail had allocation failure")
+ }
+ ty::tls::with(|tcx| {
+ tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation")
+ });
+ InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
+ })?;
+ // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]>
+ let bytes = unsafe { bytes.assume_init() };
+ Ok(Allocation {
+ bytes,
+ relocations: Relocations::new(),
+ init_mask: InitMask::new(size, false),
+ align,
+ mutability: Mutability::Mut,
+ extra: (),
+ })
+ }
+}
+
+impl Allocation {
+ /// Adjust allocation from the ones in tcx to a custom Machine instance
+ /// with a different Provenance and Extra type.
+ pub fn adjust_from_tcx<Prov, Extra, Err>(
+ self,
+ cx: &impl HasDataLayout,
+ extra: Extra,
+ mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>,
+ ) -> Result<Allocation<Prov, Extra>, Err> {
+ // Compute new pointer provenance, which also adjusts the bytes.
+ let mut bytes = self.bytes;
+ let mut new_relocations = Vec::with_capacity(self.relocations.0.len());
+ let ptr_size = cx.data_layout().pointer_size.bytes_usize();
+ let endian = cx.data_layout().endian;
+ for &(offset, alloc_id) in self.relocations.iter() {
+ let idx = offset.bytes_usize();
+ let ptr_bytes = &mut bytes[idx..idx + ptr_size];
+ let bits = read_target_uint(endian, ptr_bytes).unwrap();
+ let (ptr_prov, ptr_offset) =
+ adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
+ write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
+ new_relocations.push((offset, ptr_prov));
+ }
+ // Create allocation.
+ Ok(Allocation {
+ bytes,
+ relocations: Relocations::from_presorted(new_relocations),
+ init_mask: self.init_mask,
+ align: self.align,
+ mutability: self.mutability,
+ extra,
+ })
+ }
+}
+
+/// Raw accessors. Provide access to otherwise private bytes.
+impl<Prov, Extra> Allocation<Prov, Extra> {
+ pub fn len(&self) -> usize {
+ self.bytes.len()
+ }
+
+ pub fn size(&self) -> Size {
+ Size::from_bytes(self.len())
+ }
+
+ /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs
+ /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the
+ /// edges) at all.
+ /// This must not be used for reads affecting the interpreter execution.
+ pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
+ &self.bytes[range]
+ }
+
+ /// Returns the mask indicating which bytes are initialized.
+ pub fn init_mask(&self) -> &InitMask {
+ &self.init_mask
+ }
+
+ /// Returns the relocation list.
+ pub fn relocations(&self) -> &Relocations<Prov> {
+ &self.relocations
+ }
+}
+
+/// Byte accessors.
+impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
+ /// This is the entirely abstraction-violating way to just grab the raw bytes without
+ /// caring about relocations. It just deduplicates some code between `read_scalar`
+ /// and `get_bytes_internal`.
+ fn get_bytes_even_more_internal(&self, range: AllocRange) -> &[u8] {
+ &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
+ }
+
+ /// The last argument controls whether we error out when there are uninitialized or pointer
+ /// bytes. However, we *always* error when there are relocations overlapping the edges of the
+ /// range.
+ ///
+ /// You should never call this, call `get_bytes` or `get_bytes_with_uninit_and_ptr` instead,
+ ///
+ /// This function also guarantees that the resulting pointer will remain stable
+ /// even when new allocations are pushed to the `HashMap`. `mem_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,
+ range: AllocRange,
+ check_init_and_ptr: bool,
+ ) -> AllocResult<&[u8]> {
+ if check_init_and_ptr {
+ self.check_init(range)?;
+ self.check_relocations(cx, range)?;
+ } else {
+ // We still don't want relocations on the *edges*.
+ self.check_relocation_edges(cx, range)?;
+ }
+
+ Ok(self.get_bytes_even_more_internal(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, range: AllocRange) -> AllocResult<&[u8]> {
+ self.get_bytes_internal(cx, range, true)
+ }
+
+ /// It is the caller's responsibility to handle uninitialized 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_uninit_and_ptr(
+ &self,
+ cx: &impl HasDataLayout,
+ range: AllocRange,
+ ) -> AllocResult<&[u8]> {
+ self.get_bytes_internal(cx, range, 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,
+ range: AllocRange,
+ ) -> AllocResult<&mut [u8]> {
+ self.mark_init(range, true);
+ self.clear_relocations(cx, range)?;
+
+ Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
+ }
+
+ /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
+ pub fn get_bytes_mut_ptr(
+ &mut self,
+ cx: &impl HasDataLayout,
+ range: AllocRange,
+ ) -> AllocResult<*mut [u8]> {
+ self.mark_init(range, true);
+ self.clear_relocations(cx, range)?;
+
+ assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
+ let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
+ let len = range.end().bytes_usize() - range.start.bytes_usize();
+ Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len))
+ }
+}
+
+/// Reading and writing.
+impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
+ /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
+ /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the
+ /// given range contains no uninitialized bytes/relocations.
+ pub fn check_bytes(
+ &self,
+ cx: &impl HasDataLayout,
+ range: AllocRange,
+ allow_uninit: bool,
+ allow_ptr: bool,
+ ) -> AllocResult {
+ // Check bounds and relocations on the edges.
+ self.get_bytes_with_uninit_and_ptr(cx, range)?;
+ // Check uninit and ptr.
+ if !allow_uninit {
+ self.check_init(range)?;
+ }
+ if !allow_ptr {
+ self.check_relocations(cx, range)?;
+ }
+ Ok(())
+ }
+
+ /// Reads a *non-ZST* scalar.
+ ///
+ /// If `read_provenance` is `true`, this will also read provenance; otherwise (if the machine
+ /// supports that) provenance is entirely ignored.
+ ///
+ /// ZSTs can't be read because 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,
+ range: AllocRange,
+ read_provenance: bool,
+ ) -> AllocResult<ScalarMaybeUninit<Prov>> {
+ if read_provenance {
+ assert_eq!(range.size, cx.data_layout().pointer_size);
+ }
+
+ // First and foremost, if anything is uninit, bail.
+ if self.is_init(range).is_err() {
+ // This inflates uninitialized bytes to the entire scalar, even if only a few
+ // bytes are uninitialized.
+ return Ok(ScalarMaybeUninit::Uninit);
+ }
+
+ // If we are doing a pointer read, and there is a relocation exactly where we
+ // are reading, then we can put data and relocation back together and return that.
+ if read_provenance && let Some(&prov) = self.relocations.get(&range.start) {
+ // We already checked init and relocations, so we can use this function.
+ let bytes = self.get_bytes_even_more_internal(range);
+ let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
+ let ptr = Pointer::new(prov, Size::from_bytes(bits));
+ return Ok(ScalarMaybeUninit::from_pointer(ptr, cx));
+ }
+
+ // If we are *not* reading a pointer, and we can just ignore relocations,
+ // then do exactly that.
+ if !read_provenance && Prov::OFFSET_IS_ADDR {
+ // We just strip provenance.
+ let bytes = self.get_bytes_even_more_internal(range);
+ let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
+ return Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size)));
+ }
+
+ // It's complicated. Better make sure there is no provenance anywhere.
+ // FIXME: If !OFFSET_IS_ADDR, this is the best we can do. But if OFFSET_IS_ADDR, then
+ // `read_pointer` is true and we ideally would distinguish the following two cases:
+ // - The entire `range` is covered by 2 relocations for the same provenance.
+ // Then we should return a pointer with that provenance.
+ // - The range has inhomogeneous provenance. Then we should return just the
+ // underlying bits.
+ let bytes = self.get_bytes(cx, range)?;
+ let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
+ Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size)))
+ }
+
+ /// Writes a *non-ZST* scalar.
+ ///
+ /// ZSTs can't be read because 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.
+ #[instrument(skip(self, cx), level = "debug")]
+ pub fn write_scalar(
+ &mut self,
+ cx: &impl HasDataLayout,
+ range: AllocRange,
+ val: ScalarMaybeUninit<Prov>,
+ ) -> AllocResult {
+ assert!(self.mutability == Mutability::Mut);
+
+ let val = match val {
+ ScalarMaybeUninit::Scalar(scalar) => scalar,
+ ScalarMaybeUninit::Uninit => {
+ return self.write_uninit(cx, range);
+ }
+ };
+
+ // `to_bits_or_ptr_internal` is the right method because we just want to store this data
+ // as-is into memory.
+ let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? {
+ Err(val) => {
+ let (provenance, offset) = val.into_parts();
+ (u128::from(offset.bytes()), Some(provenance))
+ }
+ Ok(data) => (data, None),
+ };
+
+ let endian = cx.data_layout().endian;
+ let dst = self.get_bytes_mut(cx, range)?;
+ write_target_uint(endian, dst, bytes).unwrap();
+
+ // See if we have to also write a relocation.
+ if let Some(provenance) = provenance {
+ self.relocations.0.insert(range.start, provenance);
+ }
+
+ Ok(())
+ }
+
+ /// Write "uninit" to the given memory range.
+ pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+ self.mark_init(range, false);
+ self.clear_relocations(cx, range)?;
+ return Ok(());
+ }
+}
+
+/// Relocations.
+impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
+ /// Returns all relocations overlapping with the given pointer-offset pair.
+ fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] {
+ // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
+ // the beginning of this range.
+ let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
+ self.relocations.range(Size::from_bytes(start)..range.end())
+ }
+
+ /// Returns whether this allocation has relocations overlapping with the given range.
+ ///
+ /// Note: this function exists to allow `get_relocations` to be private, in order to somewhat
+ /// limit access to relocations outside of the `Allocation` abstraction.
+ ///
+ pub fn has_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool {
+ !self.get_relocations(cx, range).is_empty()
+ }
+
+ /// Checks that there are no relocations overlapping with the given range.
+ #[inline(always)]
+ fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+ if self.has_relocations(cx, range) { Err(AllocError::ReadPointerAsBytes) } else { Ok(()) }
+ }
+
+ /// 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, range: AllocRange) -> AllocResult
+ where
+ Prov: Provenance,
+ {
+ // 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, range);
+ if relocations.is_empty() {
+ return Ok(());
+ }
+
+ (
+ relocations.first().unwrap().0,
+ relocations.last().unwrap().0 + cx.data_layout().pointer_size,
+ )
+ };
+ let start = range.start;
+ let end = range.end();
+
+ // We need to handle clearing the relocations from parts of a pointer.
+ // FIXME: Miri should preserve partial relocations; see
+ // https://github.com/rust-lang/miri/issues/2181.
+ if first < start {
+ if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE {
+ return Err(AllocError::PartialPointerOverwrite(first));
+ }
+ warn!(
+ "Partial pointer overwrite! De-initializing memory at offsets {first:?}..{start:?}."
+ );
+ self.init_mask.set_range(first, start, false);
+ }
+ if last > end {
+ if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE {
+ return Err(AllocError::PartialPointerOverwrite(
+ last - cx.data_layout().pointer_size,
+ ));
+ }
+ warn!(
+ "Partial pointer overwrite! De-initializing memory at offsets {end:?}..{last:?}."
+ );
+ self.init_mask.set_range(end, last, false);
+ }
+
+ // Forget all the relocations.
+ // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine,
+ // i.e., this will not remove any other relocations just after the ones we care about.
+ self.relocations.0.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, range: AllocRange) -> AllocResult {
+ self.check_relocations(cx, alloc_range(range.start, Size::ZERO))?;
+ self.check_relocations(cx, alloc_range(range.end(), Size::ZERO))?;
+ Ok(())
+ }
+}
+
+/// "Relocations" stores the provenance information of pointers stored in memory.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+pub struct Relocations<Prov = AllocId>(SortedMap<Size, Prov>);
+
+impl<Prov> Relocations<Prov> {
+ 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, Prov)>) -> Self {
+ Relocations(SortedMap::from_presorted_elements(r))
+ }
+}
+
+impl<Prov> Deref for Relocations<Prov> {
+ type Target = SortedMap<Size, Prov>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+/// A partial, owned list of relocations to transfer into another allocation.
+///
+/// Offsets are already adjusted to the destination allocation.
+pub struct AllocationRelocations<Prov> {
+ dest_relocations: Vec<(Size, Prov)>,
+}
+
+impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
+ pub fn prepare_relocation_copy(
+ &self,
+ cx: &impl HasDataLayout,
+ src: AllocRange,
+ dest: Size,
+ count: u64,
+ ) -> AllocationRelocations<Prov> {
+ let relocations = self.get_relocations(cx, src);
+ if relocations.is_empty() {
+ return AllocationRelocations { dest_relocations: Vec::new() };
+ }
+
+ let size = src.size;
+ let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
+
+ // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
+ // is mostly filled with redundant information since it's just N copies of the same `Prov`s
+ // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
+ // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
+ // the right sequence of relocations for all N copies.
+ for i in 0..count {
+ new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
+ // compute offset for current repetition
+ let dest_offset = dest + size * i; // `Size` operations
+ (
+ // shift offsets from source allocation to destination allocation
+ (offset + dest_offset) - src.start, // `Size` operations
+ reloc,
+ )
+ }));
+ }
+
+ AllocationRelocations { dest_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.
+ ///
+ /// This is dangerous to use as it can violate internal `Allocation` invariants!
+ /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
+ pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Prov>) {
+ self.relocations.0.insert_presorted(relocations.dest_relocations);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Uninitialized 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 initialized. If it is `false` the byte is uninitialized.
+// Note: for performance reasons when interning, some of the `InitMask` fields can be partially
+// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable)]
+pub struct InitMask {
+ blocks: Vec<Block>,
+ len: Size,
+}
+
+// Const allocations are only hashed for interning. However, they can be large, making the hashing
+// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
+// big buffers like the allocation's init mask. We can partially hash some fields when they're
+// large.
+impl hash::Hash for InitMask {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ const MAX_BLOCKS_TO_HASH: usize = MAX_BYTES_TO_HASH / std::mem::size_of::<Block>();
+ const MAX_BLOCKS_LEN: usize = MAX_HASHED_BUFFER_LEN / std::mem::size_of::<Block>();
+
+ // Partially hash the `blocks` buffer when it is large. To limit collisions with common
+ // prefixes and suffixes, we hash the length and some slices of the buffer.
+ let block_count = self.blocks.len();
+ if block_count > MAX_BLOCKS_LEN {
+ // Hash the buffer's length.
+ block_count.hash(state);
+
+ // And its head and tail.
+ self.blocks[..MAX_BLOCKS_TO_HASH].hash(state);
+ self.blocks[block_count - MAX_BLOCKS_TO_HASH..].hash(state);
+ } else {
+ self.blocks.hash(state);
+ }
+
+ // Hash the other fields as usual.
+ self.len.hash(state);
+ }
+}
+
+impl InitMask {
+ pub const BLOCK_SIZE: u64 = 64;
+
+ #[inline]
+ fn bit_index(bits: Size) -> (usize, usize) {
+ // BLOCK_SIZE is the number of bits that can fit in a `Block`.
+ // Each bit in a `Block` represents the initialization state of one byte of an allocation,
+ // so we use `.bytes()` here.
+ let bits = bits.bytes();
+ let a = bits / InitMask::BLOCK_SIZE;
+ let b = bits % InitMask::BLOCK_SIZE;
+ (usize::try_from(a).unwrap(), usize::try_from(b).unwrap())
+ }
+
+ #[inline]
+ fn size_from_bit_index(block: impl TryInto<u64>, bit: impl TryInto<u64>) -> Size {
+ let block = block.try_into().ok().unwrap();
+ let bit = bit.try_into().ok().unwrap();
+ Size::from_bytes(block * InitMask::BLOCK_SIZE + bit)
+ }
+
+ pub fn new(size: Size, state: bool) -> Self {
+ let mut m = InitMask { blocks: vec![], len: Size::ZERO };
+ m.grow(size, state);
+ m
+ }
+
+ 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) = Self::bit_index(start);
+ let (blockb, bitb) = Self::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 << bita
+ } else {
+ (u64::MAX << bita) & (u64::MAX >> (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 << bita;
+ // Set `0..bitb` to `1`.
+ if bitb != 0 {
+ self.blocks[blockb] |= u64::MAX >> (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;
+ }
+ } else {
+ // Set `bita..64` to `0`.
+ self.blocks[blocka] &= !(u64::MAX << bita);
+ // Set `0..bitb` to `0`.
+ if bitb != 0 {
+ self.blocks[blockb] &= !(u64::MAX >> (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) = Self::bit_index(i);
+ (self.blocks[block] & (1 << bit)) != 0
+ }
+
+ #[inline]
+ pub fn set(&mut self, i: Size, new_state: bool) {
+ let (block, bit) = Self::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 =
+ u64::try_from(self.blocks.len()).unwrap() * Self::BLOCK_SIZE - self.len.bytes();
+ if amount.bytes() > unused_trailing_bits {
+ let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;
+ self.blocks.extend(
+ // FIXME(oli-obk): optimize this by repeating `new_state as Block`.
+ iter::repeat(0).take(usize::try_from(additional_blocks).unwrap()),
+ );
+ }
+ let start = self.len;
+ self.len += amount;
+ self.set_range_inbounds(start, start + amount, new_state); // `Size` operation
+ }
+
+ /// Returns the index of the first bit in `start..end` (end-exclusive) that is equal to is_init.
+ fn find_bit(&self, start: Size, end: Size, is_init: bool) -> Option<Size> {
+ /// A fast implementation of `find_bit`,
+ /// which skips over an entire block at a time if it's all 0s (resp. 1s),
+ /// and finds the first 1 (resp. 0) bit inside a block using `trailing_zeros` instead of a loop.
+ ///
+ /// Note that all examples below are written with 8 (instead of 64) bit blocks for simplicity,
+ /// and with the least significant bit (and lowest block) first:
+ /// ```text
+ /// 00000000|00000000
+ /// ^ ^ ^ ^
+ /// index: 0 7 8 15
+ /// ```
+ /// Also, if not stated, assume that `is_init = true`, that is, we are searching for the first 1 bit.
+ fn find_bit_fast(
+ init_mask: &InitMask,
+ start: Size,
+ end: Size,
+ is_init: bool,
+ ) -> Option<Size> {
+ /// Search one block, returning the index of the first bit equal to `is_init`.
+ fn search_block(
+ bits: Block,
+ block: usize,
+ start_bit: usize,
+ is_init: bool,
+ ) -> Option<Size> {
+ // For the following examples, assume this function was called with:
+ // bits = 0b00111011
+ // start_bit = 3
+ // is_init = false
+ // Note that, for the examples in this function, the most significant bit is written first,
+ // which is backwards compared to the comments in `find_bit`/`find_bit_fast`.
+
+ // Invert bits so we're always looking for the first set bit.
+ // ! 0b00111011
+ // bits = 0b11000100
+ let bits = if is_init { bits } else { !bits };
+ // Mask off unused start bits.
+ // 0b11000100
+ // & 0b11111000
+ // bits = 0b11000000
+ let bits = bits & (!0 << start_bit);
+ // Find set bit, if any.
+ // bit = trailing_zeros(0b11000000)
+ // bit = 6
+ if bits == 0 {
+ None
+ } else {
+ let bit = bits.trailing_zeros();
+ Some(InitMask::size_from_bit_index(block, bit))
+ }
+ }
+
+ if start >= end {
+ return None;
+ }
+
+ // Convert `start` and `end` to block indexes and bit indexes within each block.
+ // We must convert `end` to an inclusive bound to handle block boundaries correctly.
+ //
+ // For example:
+ //
+ // (a) 00000000|00000000 (b) 00000000|
+ // ^~~~~~~~~~~^ ^~~~~~~~~^
+ // start end start end
+ //
+ // In both cases, the block index of `end` is 1.
+ // But we do want to search block 1 in (a), and we don't in (b).
+ //
+ // We subtract 1 from both end positions to make them inclusive:
+ //
+ // (a) 00000000|00000000 (b) 00000000|
+ // ^~~~~~~~~~^ ^~~~~~~^
+ // start end_inclusive start end_inclusive
+ //
+ // For (a), the block index of `end_inclusive` is 1, and for (b), it's 0.
+ // This provides the desired behavior of searching blocks 0 and 1 for (a),
+ // and searching only block 0 for (b).
+ // There is no concern of overflows since we checked for `start >= end` above.
+ let (start_block, start_bit) = InitMask::bit_index(start);
+ let end_inclusive = Size::from_bytes(end.bytes() - 1);
+ let (end_block_inclusive, _) = InitMask::bit_index(end_inclusive);
+
+ // Handle first block: need to skip `start_bit` bits.
+ //
+ // We need to handle the first block separately,
+ // because there may be bits earlier in the block that should be ignored,
+ // such as the bit marked (1) in this example:
+ //
+ // (1)
+ // -|------
+ // (c) 01000000|00000000|00000001
+ // ^~~~~~~~~~~~~~~~~~^
+ // start end
+ if let Some(i) =
+ search_block(init_mask.blocks[start_block], start_block, start_bit, is_init)
+ {
+ // If the range is less than a block, we may find a matching bit after `end`.
+ //
+ // For example, we shouldn't successfully find bit (2), because it's after `end`:
+ //
+ // (2)
+ // -------|
+ // (d) 00000001|00000000|00000001
+ // ^~~~~^
+ // start end
+ //
+ // An alternative would be to mask off end bits in the same way as we do for start bits,
+ // but performing this check afterwards is faster and simpler to implement.
+ if i < end {
+ return Some(i);
+ } else {
+ return None;
+ }
+ }
+
+ // Handle remaining blocks.
+ //
+ // We can skip over an entire block at once if it's all 0s (resp. 1s).
+ // The block marked (3) in this example is the first block that will be handled by this loop,
+ // and it will be skipped for that reason:
+ //
+ // (3)
+ // --------
+ // (e) 01000000|00000000|00000001
+ // ^~~~~~~~~~~~~~~~~~^
+ // start end
+ if start_block < end_block_inclusive {
+ // This loop is written in a specific way for performance.
+ // Notably: `..end_block_inclusive + 1` is used for an inclusive range instead of `..=end_block_inclusive`,
+ // and `.zip(start_block + 1..)` is used to track the index instead of `.enumerate().skip().take()`,
+ // because both alternatives result in significantly worse codegen.
+ // `end_block_inclusive + 1` is guaranteed not to wrap, because `end_block_inclusive <= end / BLOCK_SIZE`,
+ // and `BLOCK_SIZE` (the number of bits per block) will always be at least 8 (1 byte).
+ for (&bits, block) in init_mask.blocks[start_block + 1..end_block_inclusive + 1]
+ .iter()
+ .zip(start_block + 1..)
+ {
+ if let Some(i) = search_block(bits, block, 0, is_init) {
+ // If this is the last block, we may find a matching bit after `end`.
+ //
+ // For example, we shouldn't successfully find bit (4), because it's after `end`:
+ //
+ // (4)
+ // -------|
+ // (f) 00000001|00000000|00000001
+ // ^~~~~~~~~~~~~~~~~~^
+ // start end
+ //
+ // As above with example (d), we could handle the end block separately and mask off end bits,
+ // but unconditionally searching an entire block at once and performing this check afterwards
+ // is faster and much simpler to implement.
+ if i < end {
+ return Some(i);
+ } else {
+ return None;
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ #[cfg_attr(not(debug_assertions), allow(dead_code))]
+ fn find_bit_slow(
+ init_mask: &InitMask,
+ start: Size,
+ end: Size,
+ is_init: bool,
+ ) -> Option<Size> {
+ (start..end).find(|&i| init_mask.get(i) == is_init)
+ }
+
+ let result = find_bit_fast(self, start, end, is_init);
+
+ debug_assert_eq!(
+ result,
+ find_bit_slow(self, start, end, is_init),
+ "optimized implementation of find_bit is wrong for start={:?} end={:?} is_init={} init_mask={:#?}",
+ start,
+ end,
+ is_init,
+ self
+ );
+
+ result
+ }
+}
+
+/// A contiguous chunk of initialized or uninitialized memory.
+pub enum InitChunk {
+ Init(Range<Size>),
+ Uninit(Range<Size>),
+}
+
+impl InitChunk {
+ #[inline]
+ pub fn is_init(&self) -> bool {
+ match self {
+ Self::Init(_) => true,
+ Self::Uninit(_) => false,
+ }
+ }
+
+ #[inline]
+ pub fn range(&self) -> Range<Size> {
+ match self {
+ Self::Init(r) => r.clone(),
+ Self::Uninit(r) => r.clone(),
+ }
+ }
+}
+
+impl InitMask {
+ /// Checks whether the range `start..end` (end-exclusive) is entirely initialized.
+ ///
+ /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
+ /// indexes for the first contiguous span of the uninitialized access.
+ #[inline]
+ pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), AllocRange> {
+ if end > self.len {
+ return Err(AllocRange::from(self.len..end));
+ }
+
+ let uninit_start = self.find_bit(start, end, false);
+
+ match uninit_start {
+ Some(uninit_start) => {
+ let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end);
+ Err(AllocRange::from(uninit_start..uninit_end))
+ }
+ None => Ok(()),
+ }
+ }
+
+ /// Returns an iterator, yielding a range of byte indexes for each contiguous region
+ /// of initialized or uninitialized bytes inside the range `start..end` (end-exclusive).
+ ///
+ /// The iterator guarantees the following:
+ /// - Chunks are nonempty.
+ /// - Chunks are adjacent (each range's start is equal to the previous range's end).
+ /// - Chunks span exactly `start..end` (the first starts at `start`, the last ends at `end`).
+ /// - Chunks alternate between [`InitChunk::Init`] and [`InitChunk::Uninit`].
+ #[inline]
+ pub fn range_as_init_chunks(&self, start: Size, end: Size) -> InitChunkIter<'_> {
+ assert!(end <= self.len);
+
+ let is_init = if start < end {
+ self.get(start)
+ } else {
+ // `start..end` is empty: there are no chunks, so use some arbitrary value
+ false
+ };
+
+ InitChunkIter { init_mask: self, is_init, start, end }
+ }
+}
+
+/// Yields [`InitChunk`]s. See [`InitMask::range_as_init_chunks`].
+#[derive(Clone)]
+pub struct InitChunkIter<'a> {
+ init_mask: &'a InitMask,
+ /// Whether the next chunk we will return is initialized.
+ /// If there are no more chunks, contains some arbitrary value.
+ is_init: bool,
+ /// The current byte index into `init_mask`.
+ start: Size,
+ /// The end byte index into `init_mask`.
+ end: Size,
+}
+
+impl<'a> Iterator for InitChunkIter<'a> {
+ type Item = InitChunk;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.start >= self.end {
+ return None;
+ }
+
+ let end_of_chunk =
+ self.init_mask.find_bit(self.start, self.end, !self.is_init).unwrap_or(self.end);
+ let range = self.start..end_of_chunk;
+
+ let ret =
+ Some(if self.is_init { InitChunk::Init(range) } else { InitChunk::Uninit(range) });
+
+ self.is_init = !self.is_init;
+ self.start = end_of_chunk;
+
+ ret
+ }
+}
+
+/// Uninitialized bytes.
+impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
+ /// Checks whether the given range is entirely initialized.
+ ///
+ /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
+ /// indexes of the first contiguous uninitialized access.
+ fn is_init(&self, range: AllocRange) -> Result<(), AllocRange> {
+ self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
+ }
+
+ /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
+ /// error which will report the first range of bytes which is uninitialized.
+ fn check_init(&self, range: AllocRange) -> AllocResult {
+ self.is_init(range).map_err(|uninit_range| {
+ AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+ access: range,
+ uninit: uninit_range,
+ }))
+ })
+ }
+
+ fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+ if range.size.bytes() == 0 {
+ return;
+ }
+ assert!(self.mutability == Mutability::Mut);
+ self.init_mask.set_range(range.start, range.end(), is_init);
+ }
+}
+
+/// Run-length encoding of the uninit mask.
+/// Used to copy parts of a mask multiple times to another allocation.
+pub struct InitMaskCompressed {
+ /// Whether the first range is initialized.
+ initial: bool,
+ /// The lengths of ranges that are run-length encoded.
+ /// The initialization state of the ranges alternate starting with `initial`.
+ ranges: smallvec::SmallVec<[u64; 1]>,
+}
+
+impl InitMaskCompressed {
+ pub fn no_bytes_init(&self) -> bool {
+ // The `ranges` are run-length encoded and of alternating initialization state.
+ // So if `ranges.len() > 1` then the second block is an initialized range.
+ !self.initial && self.ranges.len() == 1
+ }
+}
+
+/// Transferring the initialization mask to other allocations.
+impl<Prov, Extra> Allocation<Prov, Extra> {
+ /// Creates a run-length encoding of the initialization mask; panics if range is empty.
+ ///
+ /// This is essentially a more space-efficient version of
+ /// `InitMask::range_as_init_chunks(...).collect::<Vec<_>>()`.
+ pub fn compress_uninit_range(&self, range: AllocRange) -> InitMaskCompressed {
+ // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
+ // a naive initialization mask copying algorithm would repeatedly have to read the initialization 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.
+ // Therefore we precompute a compressed version of the initialization 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 initialized / uninitialized 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 mut chunks = self.init_mask.range_as_init_chunks(range.start, range.end()).peekable();
+
+ let initial = chunks.peek().expect("range should be nonempty").is_init();
+
+ // Here we rely on `range_as_init_chunks` to yield alternating init/uninit chunks.
+ for chunk in chunks {
+ let len = chunk.range().end.bytes() - chunk.range().start.bytes();
+ ranges.push(len);
+ }
+
+ InitMaskCompressed { ranges, initial }
+ }
+
+ /// Applies multiple instances of the run-length encoding to the initialization mask.
+ ///
+ /// This is dangerous to use as it can violate internal `Allocation` invariants!
+ /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
+ pub fn mark_compressed_init_range(
+ &mut self,
+ defined: &InitMaskCompressed,
+ range: AllocRange,
+ repeat: u64,
+ ) {
+ // An optimization where we can just overwrite an entire range of initialization
+ // bits if they are going to be uniformly `1` or `0`.
+ if defined.ranges.len() <= 1 {
+ self.init_mask.set_range_inbounds(
+ range.start,
+ range.start + range.size * repeat, // `Size` operations
+ defined.initial,
+ );
+ return;
+ }
+
+ for mut j in 0..repeat {
+ j *= range.size.bytes();
+ j += range.start.bytes();
+ let mut cur = defined.initial;
+ for range in &defined.ranges {
+ let old_j = j;
+ j += range;
+ self.init_mask.set_range_inbounds(
+ Size::from_bytes(old_j),
+ Size::from_bytes(j),
+ cur,
+ );
+ cur = !cur;
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
new file mode 100644
index 000000000..cecb55578
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -0,0 +1,551 @@
+use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
+
+use crate::mir::interpret::ConstValue;
+use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree};
+
+use rustc_data_structures::sync::Lock;
+use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_macros::HashStable;
+use rustc_session::CtfeBacktrace;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{call, Align, Size};
+use std::{any::Any, backtrace::Backtrace, fmt};
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum ErrorHandled {
+ /// Already reported an error for this evaluation, and the compilation is
+ /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
+ Reported(ErrorGuaranteed),
+ /// Already emitted a lint for this evaluation.
+ Linted,
+ /// Don't emit an error, the evaluation failed because the MIR was generic
+ /// and the substs didn't fully monomorphize it.
+ TooGeneric,
+}
+
+impl From<ErrorGuaranteed> for ErrorHandled {
+ fn from(err: ErrorGuaranteed) -> ErrorHandled {
+ ErrorHandled::Reported(err)
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ ErrorHandled,
+}
+
+pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
+pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
+
+pub fn struct_error<'tcx>(
+ tcx: TyCtxtAt<'tcx>,
+ msg: &str,
+) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(InterpErrorInfo<'_>, 8);
+
+/// Packages the kind of error we got from the const code interpreter
+/// up with a Rust-level backtrace of where the error occurred.
+/// These should always be constructed by calling `.into()` on
+/// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
+/// macros for this.
+#[derive(Debug)]
+pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
+
+#[derive(Debug)]
+struct InterpErrorInfoInner<'tcx> {
+ kind: InterpError<'tcx>,
+ backtrace: Option<Box<Backtrace>>,
+}
+
+impl fmt::Display for InterpErrorInfo<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.0.kind)
+ }
+}
+
+impl<'tcx> InterpErrorInfo<'tcx> {
+ pub fn print_backtrace(&self) {
+ if let Some(backtrace) = self.0.backtrace.as_ref() {
+ print_backtrace(backtrace);
+ }
+ }
+
+ pub fn into_kind(self) -> InterpError<'tcx> {
+ let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
+ kind
+ }
+
+ #[inline]
+ pub fn kind(&self) -> &InterpError<'tcx> {
+ &self.0.kind
+ }
+}
+
+fn print_backtrace(backtrace: &Backtrace) {
+ eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
+}
+
+impl From<ErrorHandled> for InterpErrorInfo<'_> {
+ fn from(err: ErrorHandled) -> Self {
+ match err {
+ ErrorHandled::Reported(ErrorGuaranteed { .. }) | ErrorHandled::Linted => {
+ err_inval!(ReferencedConstant)
+ }
+ ErrorHandled::TooGeneric => err_inval!(TooGeneric),
+ }
+ .into()
+ }
+}
+
+impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
+ fn from(err: ErrorGuaranteed) -> Self {
+ InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
+ }
+}
+
+impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
+ fn from(kind: InterpError<'tcx>) -> Self {
+ let capture_backtrace = tls::with_opt(|tcx| {
+ if let Some(tcx) = tcx {
+ *Lock::borrow(&tcx.sess.ctfe_backtrace)
+ } else {
+ CtfeBacktrace::Disabled
+ }
+ });
+
+ let backtrace = match capture_backtrace {
+ CtfeBacktrace::Disabled => None,
+ CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
+ CtfeBacktrace::Immediate => {
+ // Print it now.
+ let backtrace = Backtrace::force_capture();
+ print_backtrace(&backtrace);
+ None
+ }
+ };
+
+ InterpErrorInfo(Box::new(InterpErrorInfoInner { 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 errors are already reported.
+ AlreadyReported(ErrorGuaranteed),
+ /// An error occurred during layout computation.
+ Layout(layout::LayoutError<'tcx>),
+ /// An error occurred during FnAbi computation: the passed --target lacks FFI support
+ /// (which unfortunately typeck does not reject).
+ /// Not using `FnAbiError` as that contains a nested `LayoutError`.
+ FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
+ /// SizeOf of unsized type was requested.
+ SizeOfUnsizedType(Ty<'tcx>),
+}
+
+impl fmt::Display for InvalidProgramInfo<'_> {
+ 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"),
+ AlreadyReported(ErrorGuaranteed { .. }) => {
+ write!(f, "encountered constants with type errors, stopping evaluation")
+ }
+ Layout(ref err) => write!(f, "{err}"),
+ FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
+ SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
+ }
+ }
+}
+
+/// Details of why a pointer had to be in-bounds.
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub enum CheckInAllocMsg {
+ /// We are dereferencing a pointer (i.e., creating a place).
+ DerefTest,
+ /// We are access memory.
+ MemoryAccessTest,
+ /// We are doing pointer arithmetic.
+ PointerArithmeticTest,
+ /// We are doing pointer offset_from.
+ OffsetFromTest,
+ /// None of the above -- generic/unspecific inbounds test.
+ InboundsTest,
+}
+
+impl fmt::Display for CheckInAllocMsg {
+ /// When this is printed as an error the context looks like this:
+ /// "{msg}{pointer} is a dangling pointer".
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match *self {
+ CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
+ CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
+ CheckInAllocMsg::PointerArithmeticTest => "out-of-bounds pointer arithmetic: ",
+ CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
+ CheckInAllocMsg::InboundsTest => "out-of-bounds pointer use: ",
+ }
+ )
+ }
+}
+
+/// Details of an access to uninitialized bytes where it is not allowed.
+#[derive(Debug)]
+pub struct UninitBytesAccess {
+ /// Range of the original memory access.
+ pub access: AllocRange,
+ /// Range of the uninit memory that was encountered. (Might not be maximal.)
+ pub uninit: AllocRange,
+}
+
+/// Information about a size mismatch.
+#[derive(Debug)]
+pub struct ScalarSizeMismatch {
+ pub target_size: u64,
+ pub data_size: u64,
+}
+
+/// Error information for when the program caused Undefined Behavior.
+pub enum UndefinedBehaviorInfo {
+ /// Free-form case. Only for errors that are never caught!
+ Ub(String),
+ /// Unreachable code was executed.
+ Unreachable,
+ /// 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,
+ /// Signed division overflowed (INT_MIN / -1).
+ DivisionOverflow,
+ /// Signed remainder overflowed (INT_MIN % -1).
+ RemainderOverflow,
+ /// Overflowing inbounds pointer arithmetic.
+ PointerArithOverflow,
+ /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
+ InvalidMeta(&'static str),
+ /// Reading a C string that does not end within its allocation.
+ UnterminatedCString(Pointer),
+ /// Dereferencing a dangling pointer after it got freed.
+ PointerUseAfterFree(AllocId),
+ /// Used a pointer outside the bounds it is valid for.
+ /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
+ PointerOutOfBounds {
+ alloc_id: AllocId,
+ alloc_size: Size,
+ ptr_offset: i64,
+ ptr_size: Size,
+ msg: CheckInAllocMsg,
+ },
+ /// Using an integer as a pointer in the wrong way.
+ DanglingIntPointer(u64, CheckInAllocMsg),
+ /// Used a pointer with bad alignment.
+ AlignmentCheckFailed {
+ required: Align,
+ has: Align,
+ },
+ /// Writing to read-only memory.
+ WriteToReadOnly(AllocId),
+ // Trying to access the data behind a function pointer.
+ DerefFunctionPointer(AllocId),
+ // Trying to access the data behind a vtable pointer.
+ DerefVTablePointer(AllocId),
+ /// The value validity check found a problem.
+ /// Should only be thrown by `validity.rs` and always point out which part of the value
+ /// is the problem.
+ ValidationFailure {
+ /// The "path" to the value in question, e.g. `.0[5].field` for a struct
+ /// field in the 6th element of an array that is the first element of a tuple.
+ path: Option<String>,
+ msg: String,
+ },
+ /// Using a non-boolean `u8` as bool.
+ InvalidBool(u8),
+ /// Using a non-character `u32` as character.
+ InvalidChar(u32),
+ /// The tag of an enum does not encode an actual discriminant.
+ InvalidTag(Scalar),
+ /// Using a pointer-not-to-a-function as function pointer.
+ InvalidFunctionPointer(Pointer),
+ /// Using a pointer-not-to-a-vtable as vtable pointer.
+ InvalidVTablePointer(Pointer),
+ /// Using a string that is not valid UTF-8,
+ InvalidStr(std::str::Utf8Error),
+ /// Using uninitialized data where it is not allowed.
+ InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>),
+ /// Working with a local that is not currently live.
+ DeadLocal,
+ /// Data size is not equal to target size.
+ ScalarSizeMismatch(ScalarSizeMismatch),
+ /// A discriminant of an uninhabited enum variant is written.
+ UninhabitedEnumVariantWritten,
+}
+
+impl fmt::Display for UndefinedBehaviorInfo {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use UndefinedBehaviorInfo::*;
+ match self {
+ Ub(msg) => write!(f, "{msg}"),
+ Unreachable => write!(f, "entering unreachable code"),
+ BoundsCheckFailed { ref len, ref index } => {
+ write!(f, "indexing out of bounds: the len is {len} but the index is {index}")
+ }
+ DivisionByZero => write!(f, "dividing by zero"),
+ RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
+ DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
+ RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
+ PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
+ InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"),
+ UnterminatedCString(p) => write!(
+ f,
+ "reading a null-terminated string starting at {p:?} with no null found before end of allocation",
+ ),
+ PointerUseAfterFree(a) => {
+ write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
+ }
+ PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => {
+ write!(
+ f,
+ "{msg}{alloc_id:?} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
+ alloc_size = alloc_size.bytes(),
+ )
+ }
+ PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!(
+ f,
+ "{msg}{alloc_id:?} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
+ alloc_size = alloc_size.bytes(),
+ ptr_size = ptr_size.bytes(),
+ ptr_size_p = pluralize!(ptr_size.bytes()),
+ ),
+ DanglingIntPointer(i, msg) => {
+ write!(
+ f,
+ "{msg}{pointer} is a dangling pointer (it has no provenance)",
+ pointer = Pointer::<Option<AllocId>>::from_addr(*i),
+ )
+ }
+ AlignmentCheckFailed { required, has } => write!(
+ f,
+ "accessing memory with alignment {has}, but alignment {required} is required",
+ has = has.bytes(),
+ required = required.bytes()
+ ),
+ WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
+ DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
+ DerefVTablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"),
+ ValidationFailure { path: None, msg } => {
+ write!(f, "constructing invalid value: {msg}")
+ }
+ ValidationFailure { path: Some(path), msg } => {
+ write!(f, "constructing invalid value at {path}: {msg}")
+ }
+ InvalidBool(b) => {
+ write!(f, "interpreting an invalid 8-bit value as a bool: 0x{b:02x}")
+ }
+ InvalidChar(c) => {
+ write!(f, "interpreting an invalid 32-bit value as a char: 0x{c:08x}")
+ }
+ InvalidTag(val) => write!(f, "enum value has invalid tag: {val:x}"),
+ InvalidFunctionPointer(p) => {
+ write!(f, "using {p:?} as function pointer but it does not point to a function")
+ }
+ InvalidVTablePointer(p) => {
+ write!(f, "using {p:?} as vtable pointer but it does not point to a vtable")
+ }
+ InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"),
+ InvalidUninitBytes(Some((alloc, info))) => write!(
+ f,
+ "reading memory at {alloc:?}{access:?}, \
+ but memory is uninitialized at {uninit:?}, \
+ and this operation requires initialized memory",
+ access = info.access,
+ uninit = info.uninit,
+ ),
+ InvalidUninitBytes(None) => write!(
+ f,
+ "using uninitialized data, but this operation requires initialized memory"
+ ),
+ DeadLocal => write!(f, "accessing a dead local variable"),
+ ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
+ f,
+ "scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead",
+ ),
+ UninhabitedEnumVariantWritten => {
+ write!(f, "writing discriminant of an uninhabited enum")
+ }
+ }
+ }
+}
+
+/// 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 dereferencing pointers at integral addresses.
+pub enum UnsupportedOpInfo {
+ /// Free-form case. Only for errors that are never caught!
+ Unsupported(String),
+ /// Encountered a pointer where we needed raw bytes.
+ ReadPointerAsBytes,
+ /// Overwriting parts of a pointer; the resulting state cannot be represented in our
+ /// `Allocation` data structure. See <https://github.com/rust-lang/miri/issues/2181>.
+ PartialPointerOverwrite(Pointer<AllocId>),
+ //
+ // The variants below are only reachable from CTFE/const prop, miri will never emit them.
+ //
+ /// Accessing thread local statics
+ ThreadLocalStatic(DefId),
+ /// Accessing an unsupported extern static.
+ ReadExternStatic(DefId),
+}
+
+impl fmt::Display for UnsupportedOpInfo {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use UnsupportedOpInfo::*;
+ match self {
+ Unsupported(ref msg) => write!(f, "{msg}"),
+ ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
+ PartialPointerOverwrite(ptr) => {
+ write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}")
+ }
+ ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"),
+ ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"),
+ }
+ }
+}
+
+/// 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 for too long.
+ ///
+ /// The exact limit is set by the `const_eval_limit` attribute.
+ StepLimitReached,
+ /// There is not enough memory to perform an allocation.
+ MemoryExhausted,
+}
+
+impl fmt::Display 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")
+ }
+ StepLimitReached => {
+ write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
+ }
+ MemoryExhausted => {
+ write!(f, "tried to allocate more memory than available to compiler")
+ }
+ }
+ }
+}
+
+/// A trait to work around not having trait object upcasting.
+pub trait AsAny: Any {
+ fn as_any(&self) -> &dyn Any;
+}
+impl<T: Any> AsAny for T {
+ #[inline(always)]
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+}
+
+/// A trait for machine-specific errors (or other "machine stop" conditions).
+pub trait MachineStopType: AsAny + fmt::Display + Send {
+ /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
+ fn is_hard_err(&self) -> bool {
+ false
+ }
+}
+
+impl dyn MachineStopType {
+ #[inline(always)]
+ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+ self.as_any().downcast_ref()
+ }
+}
+
+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),
+ /// 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 MachineStopType>),
+}
+
+pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
+
+impl fmt::Display 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(ref msg) => write!(f, "{msg}"),
+ }
+ }
+}
+
+// Forward `Debug` to `Display`, so it does not look awful.
+impl fmt::Debug for InterpError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl InterpError<'_> {
+ /// Some errors do string formatting even if the error is never printed.
+ /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
+ /// so this method lets us detect them and `bug!` on unexpected errors.
+ pub fn formatted_string(&self) -> bool {
+ matches!(
+ self,
+ InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
+ )
+ }
+
+ /// Should this error be reported as a hard error, preventing compilation, or a soft error,
+ /// causing a deny-by-default lint?
+ pub fn is_hard_err(&self) -> bool {
+ use InterpError::*;
+ match *self {
+ MachineStop(ref err) => err.is_hard_err(),
+ UndefinedBehavior(_) => true,
+ ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) => true,
+ _ => false,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
new file mode 100644
index 000000000..967f8ece1
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -0,0 +1,633 @@
+//! 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! err_machine_stop {
+ ($($tt:tt)*) => {
+ $crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
+ };
+}
+
+// In the `throw_*` macros, avoid `return` to make them work with `try {}`.
+#[macro_export]
+macro_rules! throw_unsup {
+ ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_unsup_format {
+ ($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) };
+}
+
+#[macro_export]
+macro_rules! throw_inval {
+ ($($tt:tt)*) => { do yeet err_inval!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_ub {
+ ($($tt:tt)*) => { do yeet err_ub!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_ub_format {
+ ($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
+}
+
+#[macro_export]
+macro_rules! throw_exhaust {
+ ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_machine_stop {
+ ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) };
+}
+
+mod allocation;
+mod error;
+mod pointer;
+mod queries;
+mod value;
+
+use std::convert::TryFrom;
+use std::fmt;
+use std::io;
+use std::io::{Read, Write};
+use std::num::{NonZeroU32, NonZeroU64};
+use std::sync::atomic::{AtomicU32, Ordering};
+
+use rustc_ast::LitKind;
+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_middle::ty::print::with_no_trimmed_paths;
+use rustc_serialize::{Decodable, Encodable};
+use rustc_target::abi::Endian;
+
+use crate::mir;
+use crate::ty::codec::{TyDecoder, TyEncoder};
+use crate::ty::subst::GenericArgKind;
+use crate::ty::{self, Instance, Ty, TyCtxt};
+
+pub use self::error::{
+ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
+ EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
+ MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
+ UninitBytesAccess, UnsupportedOpInfo,
+};
+
+pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
+
+pub use self::allocation::{
+ alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask,
+ Relocations,
+};
+
+pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
+
+/// Uniquely identifies one of the following:
+/// - A constant
+/// - A static
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
+#[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>,
+}
+
+impl<'tcx> GlobalId<'tcx> {
+ pub fn display(self, tcx: TyCtxt<'tcx>) -> String {
+ let instance_name = with_no_trimmed_paths!(tcx.def_path_str(self.instance.def.def_id()));
+ if let Some(promoted) = self.promoted {
+ format!("{}::{:?}", instance_name, promoted)
+ } else {
+ instance_name
+ }
+ }
+}
+
+/// 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 (`Const::from_anon_const`).
+ TypeError,
+ Reported,
+}
+
+#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct AllocId(pub NonZeroU64);
+
+// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
+// all the Miri types.
+impl fmt::Debug for AllocId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if f.alternate() { write!(f, "a{}", self.0) } else { write!(f, "alloc{}", self.0) }
+ }
+}
+
+// No "Display" since AllocIds are not usually user-visible.
+
+#[derive(TyDecodable, TyEncodable)]
+enum AllocDiscriminant {
+ Alloc,
+ Fn,
+ VTable,
+ Static,
+}
+
+pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
+ encoder: &mut E,
+ tcx: TyCtxt<'tcx>,
+ alloc_id: AllocId,
+) {
+ match tcx.global_alloc(alloc_id) {
+ 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::VTable(ty, poly_trait_ref) => {
+ trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
+ AllocDiscriminant::VTable.encode(encoder);
+ ty.encode(encoder);
+ poly_trait_ref.encode(encoder);
+ }
+ GlobalAlloc::Static(did) => {
+ assert!(!tcx.is_thread_local_static(did));
+ // References to statics doesn't need to know about their allocations,
+ // just about its `DefId`.
+ AllocDiscriminant::Static.encode(encoder);
+ did.encode(encoder);
+ }
+ }
+}
+
+// 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 {
+ #[inline]
+ 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<'tcx, D>(&self, decoder: &mut D) -> AllocId
+ where
+ D: TyDecoder<I = TyCtxt<'tcx>>,
+ {
+ // Read the index of the allocation.
+ let idx = usize::try_from(decoder.read_u32()).unwrap();
+ let pos = usize::try_from(self.state.data_offsets[idx]).unwrap();
+
+ // 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);
+ (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 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.interner().reserve_alloc_id();
+ *entry =
+ State::InProgress(TinyList::new_single(self.session_id), alloc_id);
+ Some(alloc_id)
+ }
+ AllocDiscriminant::Fn
+ | AllocDiscriminant::Static
+ | AllocDiscriminant::VTable => {
+ // 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 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 = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
+ // We already have a reserved `AllocId`.
+ let alloc_id = alloc_id.unwrap();
+ trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
+ decoder.interner().set_alloc_id_same_memory(alloc_id, alloc);
+ 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.interner().create_fn_alloc(instance);
+ alloc_id
+ }
+ AllocDiscriminant::VTable => {
+ assert!(alloc_id.is_none());
+ trace!("creating vtable alloc ID");
+ let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
+ let poly_trait_ref =
+ <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
+ trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
+ let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref);
+ alloc_id
+ }
+ AllocDiscriminant::Static => {
+ assert!(alloc_id.is_none());
+ trace!("creating extern static alloc ID");
+ let did = <DefId as Decodable<D>>::decode(decoder);
+ trace!("decoded static def-ID: {:?}", did);
+ let alloc_id = decoder.interner().create_static_alloc(did);
+ alloc_id
+ }
+ }
+ });
+
+ self.state.decoding_state[idx].with_lock(|entry| {
+ *entry = State::Done(alloc_id);
+ });
+
+ alloc_id
+ }
+}
+
+/// 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, TyDecodable, TyEncodable, HashStable)]
+pub enum GlobalAlloc<'tcx> {
+ /// The alloc ID is used as a function pointer.
+ Function(Instance<'tcx>),
+ /// This alloc ID points to a symbolic (not-reified) vtable.
+ VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'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(ConstAllocation<'tcx>),
+}
+
+impl<'tcx> GlobalAlloc<'tcx> {
+ /// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
+ #[track_caller]
+ #[inline]
+ pub fn unwrap_memory(&self) -> ConstAllocation<'tcx> {
+ match *self {
+ GlobalAlloc::Memory(mem) => mem,
+ _ => bug!("expected memory, got {:?}", self),
+ }
+ }
+
+ /// Panics if the `GlobalAlloc` is not `GlobalAlloc::Function`
+ #[track_caller]
+ #[inline]
+ pub fn unwrap_fn(&self) -> Instance<'tcx> {
+ match *self {
+ GlobalAlloc::Function(instance) => instance,
+ _ => bug!("expected function, got {:?}", self),
+ }
+ }
+
+ /// Panics if the `GlobalAlloc` is not `GlobalAlloc::VTable`
+ #[track_caller]
+ #[inline]
+ pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
+ match *self {
+ GlobalAlloc::VTable(ty, poly_trait_ref) => (ty, poly_trait_ref),
+ _ => bug!("expected vtable, got {:?}", self),
+ }
+ }
+}
+
+pub(crate) 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(crate) fn new() -> Self {
+ AllocMap {
+ alloc_map: Default::default(),
+ dedup: Default::default(),
+ next_id: AllocId(NonZeroU64::new(1).unwrap()),
+ }
+ }
+ 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
+ }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// 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_alloc_id(self) -> AllocId {
+ self.alloc_map.lock().reserve()
+ }
+
+ /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
+ /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we
+ /// don't want to dedup IDs for "real" memory!
+ fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
+ let mut alloc_map = self.alloc_map.lock();
+ match alloc {
+ GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
+ GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
+ }
+ if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
+ return alloc_id;
+ }
+ let id = alloc_map.reserve();
+ debug!("creating alloc {alloc:?} with id {id:?}");
+ alloc_map.alloc_map.insert(id, alloc.clone());
+ alloc_map.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(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(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| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
+ if is_generic {
+ // Get a fresh ID.
+ let mut alloc_map = self.alloc_map.lock();
+ let id = alloc_map.reserve();
+ alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance));
+ id
+ } else {
+ // Deduplicate.
+ self.reserve_and_set_dedup(GlobalAlloc::Function(instance))
+ }
+ }
+
+ /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
+ pub fn create_vtable_alloc(
+ self,
+ ty: Ty<'tcx>,
+ poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+ ) -> AllocId {
+ self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref))
+ }
+
+ /// 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(self, mem: ConstAllocation<'tcx>) -> AllocId {
+ let id = self.reserve_alloc_id();
+ 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 try_get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
+ self.alloc_map.lock().alloc_map.get(&id).cloned()
+ }
+
+ #[inline]
+ #[track_caller]
+ /// Panics in case the `AllocId` is dangling. Since that is impossible for `AllocId`s in
+ /// constants (as all constants must pass interning and validation that check for dangling
+ /// ids), this function is frequently used throughout rustc, but should not be used within
+ /// the miri engine.
+ pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
+ match self.try_get_global_alloc(id) {
+ Some(alloc) => alloc,
+ None => bug!("could not find allocation for {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(self, id: AllocId, mem: ConstAllocation<'tcx>) {
+ if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
+ bug!("tried to set allocation ID {id:?}, but it was already existing as {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(self, id: AllocId, mem: ConstAllocation<'tcx>) {
+ self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Methods to access integers in the target endianness
+////////////////////////////////////////////////////////////////////////////////
+
+#[inline]
+pub fn write_target_uint(
+ endianness: Endian,
+ mut target: &mut [u8],
+ data: u128,
+) -> Result<(), io::Error> {
+ // This u128 holds an "any-size uint" (since smaller uints can fits in it)
+ // So we do not write all bytes of the u128, just the "payload".
+ match endianness {
+ Endian::Little => target.write(&data.to_le_bytes())?,
+ Endian::Big => target.write(&data.to_be_bytes()[16 - target.len()..])?,
+ };
+ debug_assert!(target.len() == 0); // We should have filled the target buffer.
+ Ok(())
+}
+
+#[inline]
+pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, io::Error> {
+ // This u128 holds an "any-size uint" (since smaller uints can fits in it)
+ let mut buf = [0u8; std::mem::size_of::<u128>()];
+ // So we do not read exactly 16 bytes into the u128, just the "payload".
+ let uint = match endianness {
+ Endian::Little => {
+ source.read(&mut buf)?;
+ Ok(u128::from_le_bytes(buf))
+ }
+ Endian::Big => {
+ source.read(&mut buf[16 - source.len()..])?;
+ Ok(u128::from_be_bytes(buf))
+ }
+ };
+ debug_assert!(source.len() == 0); // We should have consumed the source buffer.
+ uint
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
new file mode 100644
index 000000000..384954cbb
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -0,0 +1,307 @@
+use super::{AllocId, InterpResult};
+
+use rustc_macros::HashStable;
+use rustc_target::abi::{HasDataLayout, Size};
+
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
+
+////////////////////////////////////////////////////////////////////////////////
+// Pointer arithmetic
+////////////////////////////////////////////////////////////////////////////////
+
+pub trait PointerArithmetic: HasDataLayout {
+ // These are not supposed to be overridden.
+
+ #[inline(always)]
+ fn pointer_size(&self) -> Size {
+ self.data_layout().pointer_size
+ }
+
+ #[inline(always)]
+ fn max_size_of_val(&self) -> Size {
+ Size::from_bytes(self.machine_isize_max())
+ }
+
+ #[inline]
+ fn machine_usize_max(&self) -> u64 {
+ self.pointer_size().unsigned_int_max().try_into().unwrap()
+ }
+
+ #[inline]
+ fn machine_isize_min(&self) -> i64 {
+ self.pointer_size().signed_int_min().try_into().unwrap()
+ }
+
+ #[inline]
+ fn machine_isize_max(&self) -> i64 {
+ self.pointer_size().signed_int_max().try_into().unwrap()
+ }
+
+ #[inline]
+ fn machine_usize_to_isize(&self, val: u64) -> i64 {
+ let val = val as i64;
+ // Now wrap-around into the machine_isize range.
+ if val > self.machine_isize_max() {
+ // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into
+ // i64.
+ debug_assert!(self.pointer_size().bits() < 64);
+ let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
+ val - i64::try_from(max_usize_plus_1).unwrap()
+ } else {
+ val
+ }
+ }
+
+ /// 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 = u128::from(val);
+ let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
+ (u64::try_from(val % max_ptr_plus_1).unwrap(), over || val >= max_ptr_plus_1)
+ }
+
+ #[inline]
+ fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
+ // We do not need to check if i fits in a machine usize. If it doesn't,
+ // either the wrapping_add will wrap or res will not fit in a pointer.
+ let res = val.overflowing_add(i);
+ self.truncate_to_ptr(res)
+ }
+
+ #[inline]
+ fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
+ // We need to make sure that i fits in a machine isize.
+ let n = i.unsigned_abs();
+ if i >= 0 {
+ let (val, over) = self.overflowing_offset(val, n);
+ (val, over || i > self.machine_isize_max())
+ } else {
+ let res = val.overflowing_sub(n);
+ let (val, over) = self.truncate_to_ptr(res);
+ (val, over || i < self.machine_isize_min())
+ }
+ }
+
+ #[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, i);
+ if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
+ }
+}
+
+impl<T: HasDataLayout> PointerArithmetic for T {}
+
+/// This trait abstracts over the kind of provenance that is associated with a `Pointer`. It is
+/// mostly opaque; the `Machine` trait extends it with some more operations that also have access to
+/// some global state.
+/// We don't actually care about this `Debug` bound (we use `Provenance::fmt` to format the entire
+/// pointer), but `derive` adds some unnecessary bounds.
+pub trait Provenance: Copy + fmt::Debug {
+ /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
+ /// If `true, ptr-to-int casts work by simply discarding the provenance.
+ /// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
+ const OFFSET_IS_ADDR: bool;
+
+ /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten
+ /// (this avoids a separate trait in `allocation.rs` just for this purpose).
+ const ERR_ON_PARTIAL_PTR_OVERWRITE: bool;
+
+ /// Determines how a pointer should be printed.
+ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ where
+ Self: Sized;
+
+ /// If `OFFSET_IS_ADDR == false`, provenance must always be able to
+ /// identify the allocation this ptr points to (i.e., this must return `Some`).
+ /// Otherwise this function is best-effort (but must agree with `Machine::ptr_get_alloc`).
+ /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
+ fn get_alloc_id(self) -> Option<AllocId>;
+}
+
+impl Provenance for AllocId {
+ // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*,
+ // so ptr-to-int casts are not possible (since we do not know the global physical offset).
+ const OFFSET_IS_ADDR: bool = false;
+
+ // For now, do not allow this, so that we keep our options open.
+ const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = true;
+
+ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Forward `alternate` flag to `alloc_id` printing.
+ if f.alternate() {
+ write!(f, "{:#?}", ptr.provenance)?;
+ } else {
+ write!(f, "{:?}", ptr.provenance)?;
+ }
+ // Print offset only if it is non-zero.
+ if ptr.offset.bytes() > 0 {
+ write!(f, "+{:#x}", ptr.offset.bytes())?;
+ }
+ Ok(())
+ }
+
+ fn get_alloc_id(self) -> Option<AllocId> {
+ Some(self)
+ }
+}
+
+/// Represents a pointer in the Miri engine.
+///
+/// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
+#[derive(HashStable)]
+pub struct Pointer<Prov = AllocId> {
+ pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type)
+ pub provenance: Prov,
+}
+
+static_assert_size!(Pointer, 16);
+// `Option<Prov>` pointers are also passed around quite a bit
+// (but not stored in permanent machine state).
+static_assert_size!(Pointer<Option<AllocId>>, 16);
+
+// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
+// all the Miri types.
+impl<Prov: Provenance> fmt::Debug for Pointer<Prov> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Provenance::fmt(self, f)
+ }
+}
+
+impl<Prov: Provenance> fmt::Debug for Pointer<Option<Prov>> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.provenance {
+ Some(prov) => Provenance::fmt(&Pointer::new(prov, self.offset), f),
+ None => write!(f, "{:#x}[noalloc]", self.offset.bytes()),
+ }
+ }
+}
+
+impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.provenance.is_none() && self.offset.bytes() == 0 {
+ write!(f, "null pointer")
+ } else {
+ fmt::Debug::fmt(self, f)
+ }
+ }
+}
+
+/// 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<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> {
+ #[inline(always)]
+ fn from(ptr: Pointer<Prov>) -> Self {
+ let (prov, offset) = ptr.into_parts();
+ Pointer::new(Some(prov), offset)
+ }
+}
+
+impl<Prov> Pointer<Option<Prov>> {
+ /// Convert this pointer that *might* have a provenance into a pointer that *definitely* has a
+ /// provenance, or an absolute address.
+ ///
+ /// This is rarely what you want; call `ptr_try_get_alloc_id` instead.
+ pub fn into_pointer_or_addr(self) -> Result<Pointer<Prov>, Size> {
+ match self.provenance {
+ Some(prov) => Ok(Pointer::new(prov, self.offset)),
+ None => Err(self.offset),
+ }
+ }
+
+ /// Returns the absolute address the pointer points to.
+ /// Only works if Prov::OFFSET_IS_ADDR is true!
+ pub fn addr(self) -> Size
+ where
+ Prov: Provenance,
+ {
+ assert!(Prov::OFFSET_IS_ADDR);
+ self.offset
+ }
+}
+
+impl<Prov> Pointer<Option<Prov>> {
+ #[inline(always)]
+ pub fn from_addr(addr: u64) -> Self {
+ Pointer { provenance: None, offset: Size::from_bytes(addr) }
+ }
+
+ #[inline(always)]
+ pub fn null() -> Self {
+ Pointer::from_addr(0)
+ }
+}
+
+impl<'tcx, Prov> Pointer<Prov> {
+ #[inline(always)]
+ pub fn new(provenance: Prov, offset: Size) -> Self {
+ Pointer { provenance, offset }
+ }
+
+ /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`!
+ /// This function must only be used in the implementation of `Machine::ptr_get_alloc`,
+ /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`.
+ #[inline(always)]
+ pub fn into_parts(self) -> (Prov, Size) {
+ (self.provenance, self.offset)
+ }
+
+ pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self {
+ Pointer { provenance: f(self.provenance), ..self }
+ }
+
+ #[inline]
+ pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
+ Ok(Pointer {
+ offset: Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
+ ..self
+ })
+ }
+
+ #[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());
+ let ptr = Pointer { offset: Size::from_bytes(res), ..self };
+ (ptr, 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 {
+ offset: Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
+ ..self
+ })
+ }
+
+ #[inline]
+ pub fn overflowing_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> (Self, bool) {
+ let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
+ let ptr = Pointer { offset: Size::from_bytes(res), ..self };
+ (ptr, over)
+ }
+
+ #[inline(always)]
+ pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
+ self.overflowing_signed_offset(i, cx).0
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
new file mode 100644
index 000000000..786927e2d
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -0,0 +1,217 @@
+use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
+
+use crate::mir;
+use crate::ty::subst::InternalSubsts;
+use crate::ty::visit::TypeVisitable;
+use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
+use rustc_hir::def_id::DefId;
+use rustc_span::{Span, DUMMY_SP};
+
+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.
+ #[instrument(skip(self), level = "debug")]
+ pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'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 of 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_normalized(self);
+ self.const_eval_global_id(param_env, cid, None)
+ }
+ /// 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.
+ #[instrument(level = "debug", skip(self))]
+ pub fn const_eval_resolve(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ ct: ty::Unevaluated<'tcx>,
+ span: Option<Span>,
+ ) -> EvalToConstValueResult<'tcx> {
+ // Cannot resolve `Unevaluated` constants that contain inference
+ // variables. We reject those here since `resolve_opt_const_arg`
+ // would fail otherwise.
+ //
+ // When trying to evaluate constants containing inference variables,
+ // use `Infcx::const_eval_resolve` instead.
+ if ct.substs.has_infer_types_or_consts() {
+ bug!("did not expect inference variables here");
+ }
+
+ match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
+ Ok(Some(instance)) => {
+ let cid = GlobalId { instance, promoted: ct.promoted };
+ self.const_eval_global_id(param_env, cid, span)
+ }
+ Ok(None) => Err(ErrorHandled::TooGeneric),
+ Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
+ }
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ pub fn const_eval_resolve_for_typeck(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ ct: ty::Unevaluated<'tcx>,
+ span: Option<Span>,
+ ) -> EvalToValTreeResult<'tcx> {
+ // Cannot resolve `Unevaluated` constants that contain inference
+ // variables. We reject those here since `resolve_opt_const_arg`
+ // would fail otherwise.
+ //
+ // When trying to evaluate constants containing inference variables,
+ // use `Infcx::const_eval_resolve` instead.
+ if ct.substs.has_infer_types_or_consts() {
+ bug!("did not expect inference variables here");
+ }
+
+ match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
+ Ok(Some(instance)) => {
+ let cid = GlobalId { instance, promoted: ct.promoted };
+ self.const_eval_global_id_for_typeck(param_env, cid, span)
+ }
+ Ok(None) => Err(ErrorHandled::TooGeneric),
+ Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
+ }
+ }
+
+ pub fn const_eval_instance(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ instance: ty::Instance<'tcx>,
+ span: Option<Span>,
+ ) -> EvalToConstValueResult<'tcx> {
+ self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
+ }
+
+ /// Evaluate a constant to a `ConstValue`.
+ #[instrument(skip(self), level = "debug")]
+ pub fn const_eval_global_id(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ cid: GlobalId<'tcx>,
+ span: Option<Span>,
+ ) -> EvalToConstValueResult<'tcx> {
+ let param_env = param_env.with_const();
+ // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
+ // improve caching of queries.
+ let inputs = self.erase_regions(param_env.and(cid));
+ if let Some(span) = span {
+ self.at(span).eval_to_const_value_raw(inputs)
+ } else {
+ self.eval_to_const_value_raw(inputs)
+ }
+ }
+
+ /// Evaluate a constant to a type-level constant.
+ #[instrument(skip(self), level = "debug")]
+ pub fn const_eval_global_id_for_typeck(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ cid: GlobalId<'tcx>,
+ span: Option<Span>,
+ ) -> EvalToValTreeResult<'tcx> {
+ let param_env = param_env.with_const();
+ debug!(?param_env);
+ // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
+ // improve caching of queries.
+ let inputs = self.erase_regions(param_env.and(cid));
+ debug!(?inputs);
+ if let Some(span) = span {
+ self.at(span).eval_to_valtree(inputs)
+ } else {
+ self.eval_to_valtree(inputs)
+ }
+ }
+
+ /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+ #[inline(always)]
+ pub fn eval_static_initializer(
+ self,
+ def_id: DefId,
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
+ self.at(DUMMY_SP).eval_static_initializer(def_id)
+ }
+}
+
+impl<'tcx> TyCtxtAt<'tcx> {
+ /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+ pub fn eval_static_initializer(
+ self,
+ def_id: DefId,
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
+ trace!("eval_static_initializer: Need to compute {:?}", def_id);
+ assert!(self.is_static(def_id));
+ let instance = ty::Instance::mono(*self, def_id);
+ let gid = GlobalId { instance, promoted: None };
+ self.eval_to_allocation(gid, ty::ParamEnv::reveal_all())
+ }
+
+ /// Evaluate anything constant-like, returning the allocation of the final memory.
+ fn eval_to_allocation(
+ self,
+ gid: GlobalId<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
+ let param_env = param_env.with_const();
+ trace!("eval_to_allocation: Need to compute {:?}", gid);
+ let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
+ Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
+ }
+}
+
+impl<'tcx> TyCtxtEnsure<'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.
+ #[instrument(skip(self), level = "debug")]
+ pub fn const_eval_poly(self, def_id: DefId) {
+ // 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 of them are
+ // encountered.
+ let substs = InternalSubsts::identity_for_item(self.tcx, def_id);
+ let instance = ty::Instance::new(def_id, substs);
+ let cid = GlobalId { instance, promoted: None };
+ let param_env =
+ self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx).with_const();
+ // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
+ // improve caching of queries.
+ let inputs = self.tcx.erase_regions(param_env.and(cid));
+ self.eval_to_const_value_raw(inputs)
+ }
+
+ /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+ pub fn eval_static_initializer(self, def_id: DefId) {
+ trace!("eval_static_initializer: Need to compute {:?}", def_id);
+ assert!(self.tcx.is_static(def_id));
+ let instance = ty::Instance::mono(self.tcx, def_id);
+ let gid = GlobalId { instance, promoted: None };
+ let param_env = ty::ParamEnv::reveal_all().with_const();
+ trace!("eval_to_allocation: Need to compute {:?}", gid);
+ self.eval_to_allocation_raw(param_env.and(gid))
+ }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// Destructure a mir constant ADT or array into its variant index and its field values.
+ /// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version.
+ pub fn destructure_mir_constant(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ constant: mir::ConstantKind<'tcx>,
+ ) -> mir::DestructuredMirConstant<'tcx> {
+ self.try_destructure_mir_constant(param_env.and(constant)).unwrap()
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
new file mode 100644
index 000000000..834c114ee
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -0,0 +1,651 @@
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
+
+use rustc_apfloat::{
+ ieee::{Double, Single},
+ Float,
+};
+use rustc_macros::HashStable;
+use rustc_target::abi::{HasDataLayout, Size};
+
+use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
+
+use super::{
+ AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
+ ScalarSizeMismatch,
+};
+
+/// Represents the result of const evaluation via the `eval_to_allocation` query.
+#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
+pub struct ConstAlloc<'tcx> {
+ // the value lives here, at offset 0, and that allocation definitely is an `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, TyEncodable, TyDecodable, Hash)]
+#[derive(HashStable)]
+pub enum ConstValue<'tcx> {
+ /// Used only for types with `layout::abi::Scalar` ABI.
+ ///
+ /// Not using the enum `Value` to encode that this must not be `Uninit`.
+ Scalar(Scalar),
+
+ /// Only used for ZSTs.
+ ZeroSized,
+
+ /// Used only for `&[u8]` and `&str`
+ Slice { data: ConstAllocation<'tcx>, 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 `ConstAllocation`s between values
+ alloc: ConstAllocation<'tcx>,
+ /// Offset into `alloc`
+ offset: Size,
+ },
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ConstValue<'_>, 32);
+
+impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
+ type Lifted = ConstValue<'tcx>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> {
+ Some(match self {
+ ConstValue::Scalar(s) => ConstValue::Scalar(s),
+ ConstValue::ZeroSized => ConstValue::ZeroSized,
+ ConstValue::Slice { data, start, end } => {
+ ConstValue::Slice { data: tcx.lift(data)?, start, end }
+ }
+ ConstValue::ByRef { alloc, offset } => {
+ ConstValue::ByRef { alloc: tcx.lift(alloc)?, offset }
+ }
+ })
+ }
+}
+
+impl<'tcx> ConstValue<'tcx> {
+ #[inline]
+ pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
+ match *self {
+ ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
+ ConstValue::Scalar(val) => Some(val),
+ }
+ }
+
+ pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
+ Some(self.try_to_scalar()?.assert_int())
+ }
+
+ pub fn try_to_bits(&self, size: Size) -> Option<u128> {
+ self.try_to_scalar_int()?.to_bits(size).ok()
+ }
+
+ pub fn try_to_bool(&self) -> Option<bool> {
+ self.try_to_scalar_int()?.try_into().ok()
+ }
+
+ pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+ self.try_to_scalar_int()?.try_to_machine_usize(tcx).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_normalized(tcx).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 an `Allocation`, up to 16 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`
+///
+/// These variants would be private if there was a convenient way to achieve that in Rust.
+/// Do *not* match on a `Scalar`! Use the various `to_*` methods instead.
+#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
+#[derive(HashStable)]
+pub enum Scalar<Prov = AllocId> {
+ /// The raw bytes of a simple value.
+ Int(ScalarInt),
+
+ /// 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.
+ ///
+ /// We also store the size of the pointer, such that a `Scalar` always knows how big it is.
+ /// The size is always the pointer size of the current target, but this is not information
+ /// that we always have readily available.
+ Ptr(Pointer<Prov>, u8),
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(Scalar, 24);
+
+// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
+// all the Miri types.
+impl<Prov: Provenance> fmt::Debug for Scalar<Prov> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr),
+ Scalar::Int(int) => write!(f, "{:?}", int),
+ }
+ }
+}
+
+impl<Prov: Provenance> fmt::Display for Scalar<Prov> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
+ Scalar::Int(int) => write!(f, "{}", int),
+ }
+ }
+}
+
+impl<Prov: Provenance> fmt::LowerHex for Scalar<Prov> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
+ Scalar::Int(int) => write!(f, "{:#x}", int),
+ }
+ }
+}
+
+impl<Prov> From<Single> for Scalar<Prov> {
+ #[inline(always)]
+ fn from(f: Single) -> Self {
+ Scalar::from_f32(f)
+ }
+}
+
+impl<Prov> From<Double> for Scalar<Prov> {
+ #[inline(always)]
+ fn from(f: Double) -> Self {
+ Scalar::from_f64(f)
+ }
+}
+
+impl<Prov> From<ScalarInt> for Scalar<Prov> {
+ #[inline(always)]
+ fn from(ptr: ScalarInt) -> Self {
+ Scalar::Int(ptr)
+ }
+}
+
+impl<Prov> Scalar<Prov> {
+ #[inline(always)]
+ pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
+ Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap())
+ }
+
+ /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a
+ /// plain integer / "invalid" pointer).
+ pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
+ match ptr.into_parts() {
+ (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx),
+ (None, offset) => {
+ Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap())
+ }
+ }
+ }
+
+ #[inline]
+ pub fn null_ptr(cx: &impl HasDataLayout) -> Self {
+ Scalar::Int(ScalarInt::null(cx.pointer_size()))
+ }
+
+ #[inline]
+ pub fn from_bool(b: bool) -> Self {
+ Scalar::Int(b.into())
+ }
+
+ #[inline]
+ pub fn from_char(c: char) -> Self {
+ Scalar::Int(c.into())
+ }
+
+ #[inline]
+ pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
+ ScalarInt::try_from_uint(i, size).map(Scalar::Int)
+ }
+
+ #[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::Int(i.into())
+ }
+
+ #[inline]
+ pub fn from_u16(i: u16) -> Self {
+ Scalar::Int(i.into())
+ }
+
+ #[inline]
+ pub fn from_u32(i: u32) -> Self {
+ Scalar::Int(i.into())
+ }
+
+ #[inline]
+ pub fn from_u64(i: u64) -> Self {
+ Scalar::Int(i.into())
+ }
+
+ #[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> {
+ ScalarInt::try_from_int(i, size).map(Scalar::Int)
+ }
+
+ #[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_i32(i: i32) -> Self {
+ Self::from_int(i, Size::from_bits(32))
+ }
+
+ #[inline]
+ pub fn from_i64(i: i64) -> Self {
+ Self::from_int(i, Size::from_bits(64))
+ }
+
+ #[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 {
+ Scalar::Int(f.into())
+ }
+
+ #[inline]
+ pub fn from_f64(f: Double) -> Self {
+ Scalar::Int(f.into())
+ }
+
+ /// This is almost certainly not the method you want! You should dispatch on the type
+ /// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed.
+ ///
+ /// This method only exists for the benefit of low-level operations that truly need to treat the
+ /// scalar in whatever form it is.
+ ///
+ /// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in
+ /// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type.
+ #[inline]
+ pub fn to_bits_or_ptr_internal(
+ self,
+ target_size: Size,
+ ) -> Result<Result<u128, Pointer<Prov>>, ScalarSizeMismatch> {
+ assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
+ Ok(match self {
+ Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| {
+ ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() }
+ })?),
+ Scalar::Ptr(ptr, sz) => {
+ if target_size.bytes() != u64::from(sz) {
+ return Err(ScalarSizeMismatch {
+ target_size: target_size.bytes(),
+ data_size: sz.into(),
+ });
+ }
+ Err(ptr)
+ }
+ })
+ }
+}
+
+impl<'tcx, Prov: Provenance> Scalar<Prov> {
+ pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer<Option<Prov>>> {
+ match self
+ .to_bits_or_ptr_internal(cx.pointer_size())
+ .map_err(|s| err_ub!(ScalarSizeMismatch(s)))?
+ {
+ Err(ptr) => Ok(ptr.into()),
+ Ok(bits) => {
+ let addr = u64::try_from(bits).unwrap();
+ Ok(Pointer::from_addr(addr))
+ }
+ }
+ }
+
+ /// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you
+ /// likely want to use instead.
+ ///
+ /// Will perform ptr-to-int casts if needed and possible.
+ /// If that fails, we know the offset is relative, so we return an "erased" Scalar
+ /// (which is useful for error messages but not much else).
+ #[inline]
+ pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
+ match self {
+ Scalar::Int(int) => Ok(int),
+ Scalar::Ptr(ptr, sz) => {
+ if Prov::OFFSET_IS_ADDR {
+ Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
+ } else {
+ // We know `offset` is relative, since `OFFSET_IS_ADDR == false`.
+ let (prov, offset) = ptr.into_parts();
+ // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail.
+ Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz))
+ }
+ }
+ }
+ }
+
+ #[inline(always)]
+ pub fn assert_int(self) -> ScalarInt {
+ self.try_to_int().unwrap()
+ }
+
+ /// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in
+ /// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type.
+ #[inline]
+ pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
+ assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
+ self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err(
+ |size| {
+ err_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
+ target_size: target_size.bytes(),
+ data_size: size.bytes(),
+ }))
+ .into()
+ },
+ )
+ }
+
+ #[inline(always)]
+ pub fn assert_bits(self, target_size: Size) -> u128 {
+ self.to_bits(target_size).unwrap()
+ }
+
+ pub fn to_bool(self) -> InterpResult<'tcx, bool> {
+ let val = self.to_u8()?;
+ match val {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ _ => throw_ub!(InvalidBool(val)),
+ }
+ }
+
+ 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_ub!(InvalidChar(val)),
+ }
+ }
+
+ /// Converts the scalar to produce an unsigned integer of the given size.
+ /// Fails if the scalar is a pointer.
+ #[inline]
+ pub fn to_uint(self, size: Size) -> InterpResult<'tcx, u128> {
+ self.to_bits(size)
+ }
+
+ /// Converts the scalar to produce a `u8`. Fails if the scalar is a pointer.
+ pub fn to_u8(self) -> InterpResult<'tcx, u8> {
+ self.to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce a `u16`. Fails if the scalar is a pointer.
+ pub fn to_u16(self) -> InterpResult<'tcx, u16> {
+ self.to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce a `u32`. Fails if the scalar is a pointer.
+ pub fn to_u32(self) -> InterpResult<'tcx, u32> {
+ self.to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce a `u64`. Fails if the scalar is a pointer.
+ pub fn to_u64(self) -> InterpResult<'tcx, u64> {
+ self.to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce a `u128`. Fails if the scalar is a pointer.
+ pub fn to_u128(self) -> InterpResult<'tcx, u128> {
+ self.to_uint(Size::from_bits(128))
+ }
+
+ /// Converts the scalar to produce a machine-pointer-sized unsigned integer.
+ /// Fails if the scalar is a pointer.
+ pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
+ let b = self.to_uint(cx.data_layout().pointer_size)?;
+ Ok(u64::try_from(b).unwrap())
+ }
+
+ /// Converts the scalar to produce a signed integer of the given size.
+ /// Fails if the scalar is a pointer.
+ #[inline]
+ pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> {
+ let b = self.to_bits(size)?;
+ Ok(size.sign_extend(b) as i128)
+ }
+
+ /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer.
+ pub fn to_i8(self) -> InterpResult<'tcx, i8> {
+ self.to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce an `i16`. Fails if the scalar is a pointer.
+ pub fn to_i16(self) -> InterpResult<'tcx, i16> {
+ self.to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce an `i32`. Fails if the scalar is a pointer.
+ pub fn to_i32(self) -> InterpResult<'tcx, i32> {
+ self.to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce an `i64`. Fails if the scalar is a pointer.
+ pub fn to_i64(self) -> InterpResult<'tcx, i64> {
+ self.to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
+ }
+
+ /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer.
+ pub fn to_i128(self) -> InterpResult<'tcx, i128> {
+ self.to_int(Size::from_bits(128))
+ }
+
+ /// Converts the scalar to produce a machine-pointer-sized signed integer.
+ /// Fails if the scalar is a pointer.
+ pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
+ let b = self.to_int(cx.data_layout().pointer_size)?;
+ Ok(i64::try_from(b).unwrap())
+ }
+
+ #[inline]
+ pub fn to_f32(self) -> InterpResult<'tcx, Single> {
+ // Going through `u32` to check size and truncation.
+ Ok(Single::from_bits(self.to_u32()?.into()))
+ }
+
+ #[inline]
+ pub fn to_f64(self) -> InterpResult<'tcx, Double> {
+ // Going through `u64` to check size and truncation.
+ Ok(Double::from_bits(self.to_u64()?.into()))
+ }
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)]
+pub enum ScalarMaybeUninit<Prov = AllocId> {
+ Scalar(Scalar<Prov>),
+ Uninit,
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ScalarMaybeUninit, 24);
+
+impl<Prov> From<Scalar<Prov>> for ScalarMaybeUninit<Prov> {
+ #[inline(always)]
+ fn from(s: Scalar<Prov>) -> Self {
+ ScalarMaybeUninit::Scalar(s)
+ }
+}
+
+// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
+// all the Miri types.
+impl<Prov: Provenance> fmt::Debug for ScalarMaybeUninit<Prov> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ScalarMaybeUninit::Uninit => write!(f, "<uninitialized>"),
+ ScalarMaybeUninit::Scalar(s) => write!(f, "{:?}", s),
+ }
+ }
+}
+
+impl<Prov: Provenance> fmt::LowerHex for ScalarMaybeUninit<Prov> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"),
+ ScalarMaybeUninit::Scalar(s) => write!(f, "{:x}", s),
+ }
+ }
+}
+
+impl<Prov> ScalarMaybeUninit<Prov> {
+ #[inline]
+ pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
+ ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx))
+ }
+
+ #[inline]
+ pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
+ ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx))
+ }
+
+ #[inline]
+ pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Prov>> {
+ match self {
+ ScalarMaybeUninit::Scalar(scalar) => Ok(scalar),
+ ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)),
+ }
+ }
+}
+
+impl<'tcx, Prov: Provenance> ScalarMaybeUninit<Prov> {
+ #[inline(always)]
+ pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer<Option<Prov>>> {
+ self.check_init()?.to_pointer(cx)
+ }
+
+ #[inline(always)]
+ pub fn to_bool(self) -> InterpResult<'tcx, bool> {
+ self.check_init()?.to_bool()
+ }
+
+ #[inline(always)]
+ pub fn to_char(self) -> InterpResult<'tcx, char> {
+ self.check_init()?.to_char()
+ }
+
+ #[inline(always)]
+ pub fn to_f32(self) -> InterpResult<'tcx, Single> {
+ self.check_init()?.to_f32()
+ }
+
+ #[inline(always)]
+ pub fn to_f64(self) -> InterpResult<'tcx, Double> {
+ self.check_init()?.to_f64()
+ }
+
+ #[inline(always)]
+ pub fn to_u8(self) -> InterpResult<'tcx, u8> {
+ self.check_init()?.to_u8()
+ }
+
+ #[inline(always)]
+ pub fn to_u16(self) -> InterpResult<'tcx, u16> {
+ self.check_init()?.to_u16()
+ }
+
+ #[inline(always)]
+ pub fn to_u32(self) -> InterpResult<'tcx, u32> {
+ self.check_init()?.to_u32()
+ }
+
+ #[inline(always)]
+ pub fn to_u64(self) -> InterpResult<'tcx, u64> {
+ self.check_init()?.to_u64()
+ }
+
+ #[inline(always)]
+ pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
+ self.check_init()?.to_machine_usize(cx)
+ }
+
+ #[inline(always)]
+ pub fn to_i8(self) -> InterpResult<'tcx, i8> {
+ self.check_init()?.to_i8()
+ }
+
+ #[inline(always)]
+ pub fn to_i16(self) -> InterpResult<'tcx, i16> {
+ self.check_init()?.to_i16()
+ }
+
+ #[inline(always)]
+ pub fn to_i32(self) -> InterpResult<'tcx, i32> {
+ self.check_init()?.to_i32()
+ }
+
+ #[inline(always)]
+ pub fn to_i64(self) -> InterpResult<'tcx, i64> {
+ self.check_init()?.to_i64()
+ }
+
+ #[inline(always)]
+ pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
+ self.check_init()?.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.inner()
+ .get_bytes(
+ cx,
+ AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
+ )
+ .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
+ } else {
+ bug!("expected const slice, but found another const value");
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
new file mode 100644
index 000000000..7ab71f900
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -0,0 +1,2900 @@
+//! MIR datatypes and passes. See the [rustc dev guide] for more info.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
+
+use crate::mir::interpret::{
+ AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar,
+};
+use crate::mir::visit::MirVisitable;
+use crate::ty::codec::{TyDecoder, TyEncoder};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::print::{FmtPrinter, Printer};
+use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::{self, List, Ty, TyCtxt};
+use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
+
+use rustc_data_structures::captures::Captures;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::{CtorKind, Namespace};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::{self, GeneratorKind};
+use rustc_hir::{self as hir, HirId};
+use rustc_session::Session;
+use rustc_target::abi::{Size, VariantIdx};
+
+use polonius_engine::Atom;
+pub use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::graph::dominators::Dominators;
+use rustc_index::bit_set::BitMatrix;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_serialize::{Decodable, Encodable};
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+
+use either::Either;
+
+use std::borrow::Cow;
+use std::convert::TryInto;
+use std::fmt::{self, Debug, Display, Formatter, Write};
+use std::ops::{ControlFlow, Index, IndexMut};
+use std::{iter, mem};
+
+pub use self::query::*;
+pub use basic_blocks::BasicBlocks;
+
+mod basic_blocks;
+pub mod coverage;
+mod generic_graph;
+pub mod generic_graphviz;
+mod graph_cyclic_cache;
+pub mod graphviz;
+pub mod interpret;
+pub mod mono;
+pub mod patch;
+mod predecessors;
+pub mod pretty;
+mod query;
+pub mod spanview;
+mod syntax;
+pub use syntax::*;
+mod switch_sources;
+pub mod tcx;
+pub mod terminator;
+pub use terminator::*;
+
+pub mod traversal;
+mod type_foldable;
+mod type_visitable;
+pub mod visit;
+
+pub use self::generic_graph::graphviz_safe_def_name;
+pub use self::graphviz::write_mir_graphviz;
+pub use self::pretty::{
+ create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere,
+};
+
+/// Types for locals
+pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;
+
+pub trait HasLocalDecls<'tcx> {
+ fn local_decls(&self) -> &LocalDecls<'tcx>;
+}
+
+impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> {
+ #[inline]
+ fn local_decls(&self) -> &LocalDecls<'tcx> {
+ self
+ }
+}
+
+impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
+ #[inline]
+ fn local_decls(&self) -> &LocalDecls<'tcx> {
+ &self.local_decls
+ }
+}
+
+/// A streamlined trait that you can implement to create a pass; the
+/// pass will be named after the type, and it will consist of a main
+/// loop that goes over each available MIR and applies `run_pass`.
+pub trait MirPass<'tcx> {
+ fn name(&self) -> Cow<'_, str> {
+ let name = std::any::type_name::<Self>();
+ if let Some(tail) = name.rfind(':') {
+ Cow::from(&name[tail + 1..])
+ } else {
+ Cow::from(name)
+ }
+ }
+
+ /// Returns `true` if this pass is enabled with the current combination of compiler flags.
+ fn is_enabled(&self, _sess: &Session) -> bool {
+ true
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+
+ /// If this pass causes the MIR to enter a new phase, return that phase.
+ fn phase_change(&self) -> Option<MirPhase> {
+ None
+ }
+
+ fn is_mir_dump_enabled(&self) -> bool {
+ true
+ }
+}
+
+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
+ }
+}
+
+/// Where a specific `mir::Body` comes from.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
+pub struct MirSource<'tcx> {
+ pub instance: InstanceDef<'tcx>,
+
+ /// If `Some`, this is a promoted rvalue within the parent function.
+ pub promoted: Option<Promoted>,
+}
+
+impl<'tcx> MirSource<'tcx> {
+ pub fn item(def_id: DefId) -> Self {
+ MirSource {
+ instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ promoted: None,
+ }
+ }
+
+ pub fn from_instance(instance: InstanceDef<'tcx>) -> Self {
+ MirSource { instance, promoted: None }
+ }
+
+ pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
+ self.instance.with_opt_param()
+ }
+
+ #[inline]
+ pub fn def_id(&self) -> DefId {
+ self.instance.def_id()
+ }
+}
+
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
+pub struct GeneratorInfo<'tcx> {
+ /// The yield type of the function, if it is a generator.
+ pub yield_ty: Option<Ty<'tcx>>,
+
+ /// Generator drop glue.
+ pub generator_drop: Option<Body<'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: GeneratorKind,
+}
+
+/// The lowered representation of a single function.
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
+pub struct Body<'tcx> {
+ /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`]
+ /// that indexes into this vector.
+ pub basic_blocks: BasicBlocks<'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,
+
+ pub source: MirSource<'tcx>,
+
+ /// A list of source scopes; these are referenced by statements
+ /// and used for debuginfo. Indexed by a `SourceScope`.
+ pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
+
+ pub generator: Option<Box<GeneratorInfo<'tcx>>>,
+
+ /// 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: ty::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>>,
+
+ /// A span representing this MIR, for error reporting.
+ pub span: Span,
+
+ /// Constants that are required to evaluate successfully for this MIR to be well-formed.
+ /// We hold in this field all the constants we are not able to evaluate yet.
+ pub required_consts: Vec<Constant<'tcx>>,
+
+ /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
+ ///
+ /// Note that this does not actually mean that this body is not computable right now.
+ /// The repeat count in the following example is polymorphic, but can still be evaluated
+ /// without knowing anything about the type parameter `T`.
+ ///
+ /// ```rust
+ /// fn test<T>() {
+ /// let _ = [0; std::mem::size_of::<*mut T>()];
+ /// }
+ /// ```
+ ///
+ /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization
+ /// removed the last mention of all generic params. We do not want to rely on optimizations and
+ /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
+ pub is_polymorphic: bool,
+
+ pub tainted_by_errors: Option<ErrorGuaranteed>,
+}
+
+impl<'tcx> Body<'tcx> {
+ pub fn new(
+ source: MirSource<'tcx>,
+ basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+ source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
+ local_decls: LocalDecls<'tcx>,
+ user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
+ arg_count: usize,
+ var_debug_info: Vec<VarDebugInfo<'tcx>>,
+ span: Span,
+ generator_kind: Option<GeneratorKind>,
+ tainted_by_errors: Option<ErrorGuaranteed>,
+ ) -> Self {
+ // We need `arg_count` locals, and one for the return place.
+ assert!(
+ local_decls.len() > arg_count,
+ "expected at least {} locals, got {}",
+ arg_count + 1,
+ local_decls.len()
+ );
+
+ let mut body = Body {
+ phase: MirPhase::Built,
+ source,
+ basic_blocks: BasicBlocks::new(basic_blocks),
+ source_scopes,
+ generator: generator_kind.map(|generator_kind| {
+ Box::new(GeneratorInfo {
+ 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,
+ required_consts: Vec::new(),
+ is_polymorphic: false,
+ tainted_by_errors,
+ };
+ body.is_polymorphic = body.has_param_types_or_consts();
+ body
+ }
+
+ /// 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 {
+ let mut body = Body {
+ phase: MirPhase::Built,
+ source: MirSource::item(CRATE_DEF_ID.to_def_id()),
+ basic_blocks: BasicBlocks::new(basic_blocks),
+ source_scopes: IndexVec::new(),
+ generator: None,
+ local_decls: IndexVec::new(),
+ user_type_annotations: IndexVec::new(),
+ arg_count: 0,
+ spread_arg: None,
+ span: DUMMY_SP,
+ required_consts: Vec::new(),
+ var_debug_info: Vec::new(),
+ is_polymorphic: false,
+ tainted_by_errors: None,
+ };
+ body.is_polymorphic = body.has_param_types_or_consts();
+ body
+ }
+
+ #[inline]
+ pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+ &self.basic_blocks
+ }
+
+ #[inline]
+ pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+ self.basic_blocks.as_mut()
+ }
+
+ #[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 user-declared mutable locals.
+ #[inline]
+ pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + Captures<'tcx> + '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> + Captures<'tcx> + '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 {
+ (1..self.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 DoubleEndedIterator<Item = Local> + ExactSizeIterator {
+ (self.arg_count + 1..self.local_decls.len()).map(Local::new)
+ }
+
+ #[inline]
+ pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator<Item = LocalDecl<'tcx>> + 'a {
+ self.local_decls.drain(self.arg_count + 1..)
+ }
+
+ /// 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
+ }
+ }
+
+ /// Returns the return type; it always return first element from `local_decls` array.
+ #[inline]
+ pub fn return_ty(&self) -> Ty<'tcx> {
+ self.local_decls[RETURN_PLACE].ty
+ }
+
+ /// Returns the return type; it always return first element from `local_decls` array.
+ #[inline]
+ pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
+ ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty)
+ }
+
+ /// Gets the location of the terminator for the given block.
+ #[inline]
+ pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
+ Location { block: bb, statement_index: self[bb].statements.len() }
+ }
+
+ pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> {
+ let Location { block, statement_index } = location;
+ let block_data = &self.basic_blocks[block];
+ block_data
+ .statements
+ .get(statement_index)
+ .map(Either::Left)
+ .unwrap_or_else(|| Either::Right(block_data.terminator()))
+ }
+
+ #[inline]
+ pub fn yield_ty(&self) -> Option<Ty<'tcx>> {
+ self.generator.as_ref().and_then(|generator| generator.yield_ty)
+ }
+
+ #[inline]
+ pub fn generator_layout(&self) -> Option<&GeneratorLayout<'tcx>> {
+ self.generator.as_ref().and_then(|generator| generator.generator_layout.as_ref())
+ }
+
+ #[inline]
+ pub fn generator_drop(&self) -> Option<&Body<'tcx>> {
+ self.generator.as_ref().and_then(|generator| generator.generator_drop.as_ref())
+ }
+
+ #[inline]
+ pub fn generator_kind(&self) -> Option<GeneratorKind> {
+ self.generator.as_ref().map(|generator| generator.generator_kind)
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
+pub enum Safety {
+ Safe,
+ /// Unsafe because of compiler-generated unsafe code, like `await` desugaring
+ 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]
+ }
+}
+
+impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> {
+ #[inline]
+ fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
+ &mut self.basic_blocks.as_mut()[index]
+ }
+}
+
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
+pub enum ClearCrossCrate<T> {
+ Clear,
+ Set(T),
+}
+
+impl<T> ClearCrossCrate<T> {
+ pub fn as_ref(&self) -> ClearCrossCrate<&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,
+ }
+ }
+}
+
+const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
+const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
+
+impl<E: TyEncoder, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
+ #[inline]
+ fn encode(&self, e: &mut E) {
+ if E::CLEAR_CROSS_CRATE {
+ return;
+ }
+
+ match *self {
+ ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e),
+ ClearCrossCrate::Set(ref val) => {
+ TAG_CLEAR_CROSS_CRATE_SET.encode(e);
+ val.encode(e);
+ }
+ }
+ }
+}
+impl<D: TyDecoder, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
+ #[inline]
+ fn decode(d: &mut D) -> ClearCrossCrate<T> {
+ if D::CLEAR_CROSS_CRATE {
+ return ClearCrossCrate::Clear;
+ }
+
+ let discr = u8::decode(d);
+
+ match discr {
+ TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear,
+ TAG_CLEAR_CROSS_CRATE_SET => {
+ let val = T::decode(d);
+ ClearCrossCrate::Set(val)
+ }
+ tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag),
+ }
+ }
+}
+
+/// 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, TyEncodable, TyDecodable, 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,
+}
+
+impl SourceInfo {
+ #[inline]
+ pub fn outermost(span: Span) -> Self {
+ SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// 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(Clone, Copy, 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, TyEncodable, TyDecodable, 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, TyEncodable, TyDecodable)]
+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, TyEncodable, TyDecodable, 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,
+}
+
+TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx>, }
+
+mod binding_form_impl {
+ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+ use rustc_query_system::ich::StableHashingContext;
+
+ 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, TyEncodable, TyDecodable, 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,
+
+ /// `Span` of the tail expression.
+ pub span: Span,
+}
+
+/// 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, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct LocalDecl<'tcx> {
+ /// Whether this is a mutable binding (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: Option<Box<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
+ /// outside of type inference.
+ ///
+ /// This should be sound because the drop flags are fully algebraic, and
+ /// therefore don't affect the auto-trait 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: Option<Box<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::<u32>().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,
+}
+
+// `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(LocalDecl<'_>, 56);
+
+/// Extra information about a some locals that's used for diagnostics and for
+/// classifying variables into local variables, statics, etc, which is needed e.g.
+/// for unsafety checking.
+///
+/// Not used for non-StaticRef temporaries, the return place, or anonymous
+/// function parameters.
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+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 },
+ /// A temporary created that references the const with the given `DefId`
+ ConstRef { def_id: DefId },
+ /// A temporary created during the creation of an aggregate
+ /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
+ AggregateTemp,
+ /// A temporary created during the pass `Derefer` to avoid it's retagging
+ DerefTemp,
+}
+
+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 {
+ matches!(
+ self.local_info,
+ Some(box LocalInfo::User(ClearCrossCrate::Set(
+ BindingForm::Var(VarBindingForm {
+ binding_mode: ty::BindingMode::BindByValue(_),
+ opt_ty_info: _,
+ opt_match_place: _,
+ pat_span: _,
+ }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
+ )))
+ )
+ }
+
+ /// 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 {
+ matches!(
+ self.local_info,
+ Some(box LocalInfo::User(ClearCrossCrate::Set(
+ BindingForm::Var(VarBindingForm {
+ binding_mode: ty::BindingMode::BindByValue(_),
+ opt_ty_info: _,
+ opt_match_place: _,
+ pat_span: _,
+ }) | BindingForm::ImplicitSelf(_),
+ )))
+ )
+ }
+
+ /// Returns `true` if this variable is a named variable or function
+ /// parameter declared by the user.
+ #[inline]
+ pub fn is_user_variable(&self) -> bool {
+ matches!(self.local_info, Some(box LocalInfo::User(_)))
+ }
+
+ /// 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 {
+ matches!(
+ self.local_info,
+ Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)))
+ )
+ }
+
+ /// 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 {
+ matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
+ }
+
+ /// Returns `Some` if this is a reference to a thread-local static item that is used to
+ /// access that static.
+ pub fn is_ref_to_thread_local(&self) -> bool {
+ match self.local_info {
+ Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
+ _ => false,
+ }
+ }
+
+ /// Returns `true` if this is a DerefTemp
+ pub fn is_deref_temp(&self) -> bool {
+ match self.local_info {
+ Some(box LocalInfo::DerefTemp) => return true,
+ _ => (),
+ }
+ return 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: mutable, non-internal.
+ #[inline]
+ pub fn new(ty: Ty<'tcx>, span: Span) -> Self {
+ Self::with_source_info(ty, SourceInfo::outermost(span))
+ }
+
+ /// Like `LocalDecl::new`, but takes a `SourceInfo` instead of a `Span`.
+ #[inline]
+ pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self {
+ LocalDecl {
+ mutability: Mutability::Mut,
+ local_info: None,
+ internal: false,
+ is_block_tail: None,
+ ty,
+ user_ty: None,
+ source_info,
+ }
+ }
+
+ /// Converts `self` into same `LocalDecl` except tagged as internal.
+ #[inline]
+ pub fn internal(mut self) -> Self {
+ self.internal = true;
+ self
+ }
+
+ /// 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
+ }
+}
+
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub enum VarDebugInfoContents<'tcx> {
+ /// NOTE(eddyb) There's an unenforced invariant that this `Place` is
+ /// based on a `Local`, not a `Static`, and contains no indexing.
+ Place(Place<'tcx>),
+ Const(Constant<'tcx>),
+}
+
+impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
+ VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
+ }
+ }
+}
+
+/// Debug information pertaining to a user variable.
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct VarDebugInfo<'tcx> {
+ pub name: Symbol,
+
+ /// 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.
+ pub value: VarDebugInfoContents<'tcx>,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// BasicBlock
+
+rustc_index::newtype_index! {
+ /// A node in the MIR [control-flow graph][CFG].
+ ///
+ /// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes
+ /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented
+ /// as an edge in a graph between basic blocks.
+ ///
+ /// Basic blocks consist of a series of [statements][Statement], ending with a
+ /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors,
+ /// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which
+ /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is
+ /// needed because some analyses require that there are no critical edges in the CFG.
+ ///
+ /// Note that this type is just an index into [`Body.basic_blocks`](Body::basic_blocks);
+ /// the actual data that a basic block holds is in [`BasicBlockData`].
+ ///
+ /// Read more about basic blocks in the [rustc-dev-guide][guide-mir].
+ ///
+ /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
+ /// [data-flow analyses]:
+ /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis
+ /// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
+ /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/
+ 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
+
+/// Data for a basic block, including a list of its statements.
+///
+/// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+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,
+}
+
+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 convenient way to reach the terminator.
+ #[inline]
+ pub fn terminator(&self) -> &Terminator<'tcx> {
+ self.terminator.as_ref().expect("invalid terminator state")
+ }
+
+ #[inline]
+ 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::outermost(DUMMY_SP), 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"),
+ }
+ }
+
+ /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
+ pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
+ where
+ O: Debug,
+ {
+ use AssertKind::*;
+ match self {
+ BoundsCheck { ref len, ref index } => write!(
+ f,
+ "\"index out of bounds: the length is {{}} but the index is {{}}\", {:?}, {:?}",
+ len, index
+ ),
+
+ OverflowNeg(op) => {
+ write!(f, "\"attempt to negate `{{}}`, which would overflow\", {:?}", op)
+ }
+ DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {:?}", op),
+ RemainderByZero(op) => write!(
+ f,
+ "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {:?}",
+ op
+ ),
+ Overflow(BinOp::Add, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} + {{}}`, which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Sub, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} - {{}}`, which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Mul, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} * {{}}`, which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Div, l, r) => write!(
+ f,
+ "\"attempt to compute `{{}} / {{}}`, which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Rem, l, r) => write!(
+ f,
+ "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {:?}, {:?}",
+ l, r
+ ),
+ Overflow(BinOp::Shr, _, r) => {
+ write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {:?}", r)
+ }
+ Overflow(BinOp::Shl, _, r) => {
+ write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r)
+ }
+ _ => write!(f, "\"{}\"", self.description()),
+ }
+ }
+}
+
+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 length is {:?} but the index is {:?}",
+ len, index
+ ),
+ OverflowNeg(op) => write!(f, "attempt to negate `{:#?}`, which would overflow", op),
+ DivisionByZero(op) => write!(f, "attempt to divide `{:#?}` by zero", op),
+ RemainderByZero(op) => write!(
+ f,
+ "attempt to calculate the remainder of `{:#?}` with a divisor of zero",
+ op
+ ),
+ Overflow(BinOp::Add, l, r) => {
+ write!(f, "attempt to compute `{:#?} + {:#?}`, which would overflow", l, r)
+ }
+ Overflow(BinOp::Sub, l, r) => {
+ write!(f, "attempt to compute `{:#?} - {:#?}`, which would overflow", l, r)
+ }
+ Overflow(BinOp::Mul, l, r) => {
+ write!(f, "attempt to compute `{:#?} * {:#?}`, which would overflow", l, r)
+ }
+ Overflow(BinOp::Div, l, r) => {
+ write!(f, "attempt to compute `{:#?} / {:#?}`, which would overflow", l, r)
+ }
+ Overflow(BinOp::Rem, l, r) => write!(
+ f,
+ "attempt to compute the remainder of `{:#?} % {:#?}`, which would overflow",
+ l, r
+ ),
+ Overflow(BinOp::Shr, _, r) => {
+ write!(f, "attempt to shift right by `{:#?}`, which would overflow", r)
+ }
+ Overflow(BinOp::Shl, _, r) => {
+ write!(f, "attempt to shift left by `{:#?}`, which would overflow", r)
+ }
+ _ => write!(f, "{}", self.description()),
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Statements
+
+/// A statement in a basic block, including information about its source code.
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+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(all(target_arch = "x86_64", target_pointer_width = "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.
+ #[must_use = "If you don't need the statement, use `make_nop` instead"]
+ pub fn replace_nop(&mut self) -> Self {
+ Statement {
+ source_info: self.source_info,
+ kind: mem::replace(&mut self.kind, StatementKind::Nop),
+ }
+ }
+}
+
+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(box (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)
+ }
+ Deinit(ref place) => write!(fmt, "Deinit({:?})", place),
+ AscribeUserType(box (ref place, ref c_ty), ref variance) => {
+ write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
+ }
+ Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => {
+ write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
+ }
+ Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
+ CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
+ ref src,
+ ref dst,
+ ref count,
+ }) => {
+ write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
+ }
+ Nop => write!(fmt, "nop"),
+ }
+ }
+}
+
+impl<'tcx> StatementKind<'tcx> {
+ pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
+ match self {
+ StatementKind::Assign(x) => Some(x),
+ _ => None,
+ }
+ }
+
+ pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> {
+ match self {
+ StatementKind::Assign(x) => Some(x),
+ _ => None,
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Places
+
+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,
+ }
+ }
+
+ /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
+ pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
+ matches!(*self, Self::Downcast(_, x) if x == v)
+ }
+
+ /// Returns `true` if this is a `Field` projection with the given index.
+ pub fn is_field_to(&self, f: Field) -> bool {
+ matches!(*self, Self::Field(x, _) if x == f)
+ }
+}
+
+/// 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! {
+ /// A [newtype'd][wrapper] index type in the MIR [control-flow graph][CFG]
+ ///
+ /// A field (e.g., `f` in `_1.f`) is one variant of [`ProjectionElem`]. Conceptually,
+ /// rustc can identify that a field projection refers to either two different regions of memory
+ /// or the same one between the base and the 'projection element'.
+ /// Read more about projections in the [rustc-dev-guide][mir-datatypes]
+ ///
+ /// [wrapper]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#newtype
+ /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
+ /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types
+ pub struct Field {
+ derive [HashStable]
+ DEBUG_FORMAT = "field[{}]"
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct PlaceRef<'tcx> {
+ pub local: Local,
+ pub projection: &'tcx [PlaceElem<'tcx>],
+}
+
+// Once we stop implementing `Ord` for `DefId`,
+// this impl will be unnecessary. Until then, we'll
+// leave this impl in place to prevent re-adding a
+// dependnecy on the `Ord` impl for `DefId`
+impl<'tcx> !PartialOrd for PlaceRef<'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())
+ }
+
+ /// If MirPhase >= Derefered and if projection contains Deref,
+ /// It's guaranteed to be in the first place
+ pub fn has_deref(&self) -> bool {
+ // To make sure this is not accidently used in wrong mir phase
+ debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref));
+ self.projection.first() == Some(&PlaceElem::Deref)
+ }
+
+ /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
+ /// a single deref of a local.
+ #[inline(always)]
+ pub fn local_or_deref_local(&self) -> Option<Local> {
+ self.as_ref().local_or_deref_local()
+ }
+
+ /// If this place represents a local variable like `_X` with no
+ /// projections, return `Some(_X)`.
+ #[inline(always)]
+ pub fn as_local(&self) -> Option<Local> {
+ self.as_ref().as_local()
+ }
+
+ #[inline]
+ pub fn as_ref(&self) -> PlaceRef<'tcx> {
+ PlaceRef { local: self.local, projection: &self.projection }
+ }
+
+ /// Iterate over the projections in evaluation order, i.e., the first element is the base with
+ /// its projection and then subsequently more projections are added.
+ /// As a concrete example, given the place a.b.c, this would yield:
+ /// - (a, .b)
+ /// - (a.b, .c)
+ ///
+ /// Given a place without projections, the iterator is empty.
+ #[inline]
+ pub fn iter_projections(
+ self,
+ ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
+ self.as_ref().iter_projections()
+ }
+
+ /// Generates a new place by appending `more_projections` to the existing ones
+ /// and interning the result.
+ pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
+ if more_projections.is_empty() {
+ return self;
+ }
+
+ let mut v: Vec<PlaceElem<'tcx>>;
+
+ let new_projections = if self.projection.is_empty() {
+ more_projections
+ } else {
+ v = Vec::with_capacity(self.projection.len() + more_projections.len());
+ v.extend(self.projection);
+ v.extend(more_projections);
+ &v
+ };
+
+ Place { local: self.local, projection: tcx.intern_place_elems(new_projections) }
+ }
+}
+
+impl From<Local> for Place<'_> {
+ fn from(local: Local) -> Self {
+ Place { local, projection: List::empty() }
+ }
+}
+
+impl<'tcx> PlaceRef<'tcx> {
+ /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
+ /// a single deref of a local.
+ pub fn local_or_deref_local(&self) -> Option<Local> {
+ match *self {
+ PlaceRef { local, projection: [] }
+ | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
+ _ => None,
+ }
+ }
+
+ /// If MirPhase >= Derefered and if projection contains Deref,
+ /// It's guaranteed to be in the first place
+ pub fn has_deref(&self) -> bool {
+ self.projection.first() == Some(&PlaceElem::Deref)
+ }
+
+ /// If this place represents a local variable like `_X` with no
+ /// projections, return `Some(_X)`.
+ #[inline]
+ pub fn as_local(&self) -> Option<Local> {
+ match *self {
+ PlaceRef { local, projection: [] } => Some(local),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
+ if let &[ref proj_base @ .., elem] = self.projection {
+ Some((PlaceRef { local: self.local, projection: proj_base }, elem))
+ } else {
+ None
+ }
+ }
+
+ /// Iterate over the projections in evaluation order, i.e., the first element is the base with
+ /// its projection and then subsequently more projections are added.
+ /// As a concrete example, given the place a.b.c, this would yield:
+ /// - (a, .b)
+ /// - (a.b, .c)
+ ///
+ /// Given a place without projections, the iterator is empty.
+ #[inline]
+ pub fn iter_projections(
+ self,
+ ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
+ self.projection.iter().enumerate().map(move |(i, proj)| {
+ let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
+ (base, *proj)
+ })
+ }
+}
+
+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,
+ }
+}
+
+impl SourceScope {
+ /// Finds the original HirId this MIR item came from.
+ /// This is necessary after MIR optimizations, as otherwise we get a HirId
+ /// from the function that was inlined instead of the function call site.
+ pub fn lint_root<'tcx>(
+ self,
+ source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>,
+ ) -> Option<HirId> {
+ let mut data = &source_scopes[self];
+ // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it
+ // does not work as I thought it would. Needs more investigation and documentation.
+ while data.inlined.is_some() {
+ trace!(?data);
+ data = &source_scopes[data.parent_scope.unwrap()];
+ }
+ trace!(?data);
+ match &data.local_data {
+ ClearCrossCrate::Set(data) => Some(data.lint_root),
+ ClearCrossCrate::Clear => None,
+ }
+ }
+
+ /// The instance this source scope was inlined from, if any.
+ #[inline]
+ pub fn inlined_instance<'tcx>(
+ self,
+ source_scopes: &IndexVec<SourceScope, SourceScopeData<'tcx>>,
+ ) -> Option<ty::Instance<'tcx>> {
+ let scope_data = &source_scopes[self];
+ if let Some((inlined_instance, _)) = scope_data.inlined {
+ Some(inlined_instance)
+ } else if let Some(inlined_scope) = scope_data.inlined_parent_scope {
+ Some(source_scopes[inlined_scope].inlined.unwrap().0)
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct SourceScopeData<'tcx> {
+ pub span: Span,
+ pub parent_scope: Option<SourceScope>,
+
+ /// Whether this scope is the root of a scope tree of another body,
+ /// inlined into this body by the MIR inliner.
+ /// `ty::Instance` is the callee, and the `Span` is the call site.
+ pub inlined: Option<(ty::Instance<'tcx>, Span)>,
+
+ /// Nearest (transitive) parent scope (if any) which is inlined.
+ /// This is an optimization over walking up `parent_scope`
+ /// until a scope with `inlined: Some(...)` is found.
+ pub inlined_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, TyEncodable, TyDecodable, 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
+
+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.bound_type_of(def_id).subst(tcx, substs);
+ Operand::Constant(Box::new(Constant {
+ span,
+ user_ty: None,
+ literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
+ }))
+ }
+
+ pub fn is_move(&self) -> bool {
+ matches!(self, Operand::Move(..))
+ }
+
+ /// Convenience helper to make a literal-like constant from a given scalar value.
+ /// Since this is used to synthesize MIR, assumes `user_ty` is None.
+ pub fn const_from_scalar(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ val: Scalar,
+ span: Span,
+ ) -> Operand<'tcx> {
+ debug_assert!({
+ let param_env_and_ty = ty::ParamEnv::empty().and(ty);
+ let type_size = tcx
+ .layout_of(param_env_and_ty)
+ .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+ .size;
+ let scalar_size = match val {
+ Scalar::Int(int) => int.size(),
+ _ => panic!("Invalid scalar type {:?}", val),
+ };
+ scalar_size == type_size
+ });
+ Operand::Constant(Box::new(Constant {
+ span,
+ user_ty: None,
+ literal: ConstantKind::Val(ConstValue::Scalar(val), 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,
+ }
+ }
+
+ /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a
+ /// place.
+ pub fn constant(&self) -> Option<&Constant<'tcx>> {
+ match self {
+ Operand::Constant(x) => Some(&**x),
+ Operand::Copy(_) | Operand::Move(_) => None,
+ }
+ }
+
+ /// Gets the `ty::FnDef` from an operand if it's a constant function item.
+ ///
+ /// While this is unlikely in general, it's the normal case of what you'll
+ /// find as the `func` in a [`TerminatorKind::Call`].
+ pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> {
+ let const_ty = self.constant()?.literal.ty();
+ if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// Rvalues
+
+impl<'tcx> Rvalue<'tcx> {
+ /// Returns true if rvalue can be safely removed when the result is unused.
+ #[inline]
+ pub fn is_safe_to_remove(&self) -> bool {
+ match self {
+ // Pointer to int casts may be side-effects due to exposing the provenance.
+ // While the model is undecided, we should be conservative. See
+ // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
+ Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
+
+ Rvalue::Use(_)
+ | Rvalue::CopyForDeref(_)
+ | Rvalue::Repeat(_, _)
+ | Rvalue::Ref(_, _, _)
+ | Rvalue::ThreadLocalRef(_)
+ | Rvalue::AddressOf(_, _)
+ | Rvalue::Len(_)
+ | Rvalue::Cast(
+ CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress,
+ _,
+ _,
+ )
+ | Rvalue::BinaryOp(_, _)
+ | Rvalue::CheckedBinaryOp(_, _)
+ | Rvalue::NullaryOp(_, _)
+ | Rvalue::UnaryOp(_, _)
+ | Rvalue::Discriminant(_)
+ | Rvalue::Aggregate(_, _)
+ | Rvalue::ShallowInitBox(_, _) => true,
+ }
+ }
+}
+
+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,
+ }
+ }
+
+ pub fn describe_mutability(&self) -> &str {
+ match *self {
+ BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable",
+ BorrowKind::Mut { .. } => "mutable",
+ }
+ }
+}
+
+impl BinOp {
+ pub fn is_checkable(self) -> bool {
+ use self::BinOp::*;
+ matches!(self, Add | Sub | Mul | Shl | Shr)
+ }
+}
+
+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, b) => {
+ write!(fmt, "[{:?}; ", a)?;
+ pretty_print_const(b, fmt, false)?;
+ write!(fmt, "]")
+ }
+ Len(ref a) => write!(fmt, "Len({:?})", a),
+ Cast(ref kind, ref place, ref ty) => {
+ write!(fmt, "{:?} as {:?} ({:?})", place, ty, kind)
+ }
+ BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{:?}({:?}, {:?})", op, a, b),
+ CheckedBinaryOp(ref op, box (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),
+ ThreadLocalRef(did) => ty::tls::with(|tcx| {
+ let muta = tcx.static_mutability(did).unwrap().prefix_str();
+ write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
+ }),
+ 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.unstable_opts.identify_regions
+ });
+ let region = if print_region {
+ let mut region = region.to_string();
+ if !region.is_empty() {
+ region.push(' ');
+ }
+ region
+ } else {
+ // Do not even print 'static
+ String::new()
+ };
+ write!(fmt, "&{}{}{:?}", region, kind_str, place)
+ }
+
+ CopyForDeref(ref place) => write!(fmt, "deref_copy {:#?}", 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) => {
+ let fmt_tuple = |fmt: &mut Formatter<'_>, name: &str| {
+ let mut tuple_fmt = fmt.debug_tuple(name);
+ for place in places {
+ tuple_fmt.field(place);
+ }
+ tuple_fmt.finish()
+ };
+
+ match **kind {
+ AggregateKind::Array(_) => write!(fmt, "{:?}", places),
+
+ AggregateKind::Tuple => {
+ if places.is_empty() {
+ write!(fmt, "()")
+ } else {
+ fmt_tuple(fmt, "")
+ }
+ }
+
+ AggregateKind::Adt(adt_did, variant, substs, _user_ty, _) => {
+ ty::tls::with(|tcx| {
+ let variant_def = &tcx.adt_def(adt_did).variant(variant);
+ let substs = tcx.lift(substs).expect("could not lift for printing");
+ let name = FmtPrinter::new(tcx, Namespace::ValueNS)
+ .print_def_path(variant_def.def_id, substs)?
+ .into_buffer();
+
+ match variant_def.ctor_kind {
+ CtorKind::Const => fmt.write_str(&name),
+ CtorKind::Fn => fmt_tuple(fmt, &name),
+ CtorKind::Fictive => {
+ let mut struct_fmt = fmt.debug_struct(&name);
+ for (field, place) in iter::zip(&variant_def.fields, places) {
+ struct_fmt.field(field.name.as_str(), place);
+ }
+ struct_fmt.finish()
+ }
+ }
+ })
+ }
+
+ AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| {
+ let name = if tcx.sess.opts.unstable_opts.span_free_formats {
+ let substs = tcx.lift(substs).unwrap();
+ format!(
+ "[closure@{}]",
+ tcx.def_path_str_with_substs(def_id.to_def_id(), substs),
+ )
+ } else {
+ let span = tcx.def_span(def_id);
+ format!(
+ "[closure@{}]",
+ tcx.sess.source_map().span_to_diagnostic_string(span)
+ )
+ };
+ let mut struct_fmt = fmt.debug_struct(&name);
+
+ // FIXME(project-rfc-2229#48): This should be a list of capture names/places
+ if let Some(upvars) = tcx.upvars_mentioned(def_id) {
+ for (&var_id, place) in iter::zip(upvars.keys(), places) {
+ let var_name = tcx.hir().name(var_id);
+ struct_fmt.field(var_name.as_str(), place);
+ }
+ }
+
+ struct_fmt.finish()
+ }),
+
+ AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| {
+ let name = format!("[generator@{:?}]", tcx.def_span(def_id));
+ let mut struct_fmt = fmt.debug_struct(&name);
+
+ // FIXME(project-rfc-2229#48): This should be a list of capture names/places
+ if let Some(upvars) = tcx.upvars_mentioned(def_id) {
+ for (&var_id, place) in iter::zip(upvars.keys(), places) {
+ let var_name = tcx.hir().name(var_id);
+ struct_fmt.field(var_name.as_str(), place);
+ }
+ }
+
+ struct_fmt.finish()
+ }),
+ }
+ }
+
+ ShallowInitBox(ref place, ref ty) => {
+ write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty)
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// 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, Copy, PartialEq, TyEncodable, TyDecodable, Hash, 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: ConstantKind<'tcx>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
+#[derive(Lift)]
+pub enum ConstantKind<'tcx> {
+ /// This constant came from the type system
+ Ty(ty::Const<'tcx>),
+ /// This constant cannot go back into the type system, as it represents
+ /// something the type system cannot handle (e.g. pointers).
+ Val(interpret::ConstValue<'tcx>, Ty<'tcx>),
+}
+
+impl<'tcx> Constant<'tcx> {
+ pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.literal.try_to_scalar() {
+ Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
+ GlobalAlloc::Static(def_id) => {
+ assert!(!tcx.is_thread_local_static(def_id));
+ Some(def_id)
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+ }
+ #[inline]
+ pub fn ty(&self) -> Ty<'tcx> {
+ self.literal.ty()
+ }
+}
+
+impl<'tcx> ConstantKind<'tcx> {
+ /// Returns `None` if the constant is not trivially safe for use in the type system.
+ #[inline]
+ pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> {
+ match self {
+ ConstantKind::Ty(c) => Some(*c),
+ ConstantKind::Val(..) => None,
+ }
+ }
+
+ #[inline(always)]
+ pub fn ty(&self) -> Ty<'tcx> {
+ match self {
+ ConstantKind::Ty(c) => c.ty(),
+ ConstantKind::Val(_, ty) => *ty,
+ }
+ }
+
+ #[inline]
+ pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
+ match self {
+ ConstantKind::Ty(c) => match c.kind() {
+ ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
+ _ => None,
+ },
+ ConstantKind::Val(val, _) => Some(val),
+ }
+ }
+
+ #[inline]
+ pub fn try_to_scalar(self) -> Option<Scalar> {
+ match self {
+ ConstantKind::Ty(c) => match c.kind() {
+ ty::ConstKind::Value(valtree) => match valtree {
+ ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
+ ty::ValTree::Branch(_) => None,
+ },
+ _ => None,
+ },
+ ConstantKind::Val(val, _) => val.try_to_scalar(),
+ }
+ }
+
+ #[inline]
+ pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
+ Some(self.try_to_scalar()?.assert_int())
+ }
+
+ #[inline]
+ pub fn try_to_bits(self, size: Size) -> Option<u128> {
+ self.try_to_scalar_int()?.to_bits(size).ok()
+ }
+
+ #[inline]
+ pub fn try_to_bool(self) -> Option<bool> {
+ self.try_to_scalar_int()?.try_into().ok()
+ }
+
+ #[inline]
+ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ match self {
+ Self::Ty(c) => {
+ if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) {
+ match val {
+ Ok(val) => Self::Val(val, c.ty()),
+ Err(_) => Self::Ty(tcx.const_error(self.ty())),
+ }
+ } else {
+ self
+ }
+ }
+ Self::Val(_, _) => self,
+ }
+ }
+
+ /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+ #[inline]
+ pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::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 try_eval_bits(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> Option<u128> {
+ match self {
+ Self::Ty(ct) => ct.try_eval_bits(tcx, param_env, ty),
+ Self::Val(val, t) => {
+ assert_eq!(*t, ty);
+ let size =
+ tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
+ val.try_to_bits(size)
+ }
+ }
+ }
+
+ #[inline]
+ pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
+ match self {
+ Self::Ty(ct) => ct.try_eval_bool(tcx, param_env),
+ Self::Val(val, _) => val.try_to_bool(),
+ }
+ }
+
+ #[inline]
+ pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u64> {
+ match self {
+ Self::Ty(ct) => ct.try_eval_usize(tcx, param_env),
+ Self::Val(val, _) => val.try_to_machine_usize(tcx),
+ }
+ }
+
+ #[inline]
+ pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
+ Self::Val(val, ty)
+ }
+
+ pub fn from_bits(
+ tcx: TyCtxt<'tcx>,
+ bits: u128,
+ param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+ ) -> Self {
+ let size = tcx
+ .layout_of(param_env_ty)
+ .unwrap_or_else(|e| {
+ bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
+ })
+ .size;
+ let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
+
+ Self::Val(cv, param_env_ty.value)
+ }
+
+ #[inline]
+ pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
+ let cv = ConstValue::from_bool(v);
+ Self::Val(cv, tcx.types.bool)
+ }
+
+ #[inline]
+ pub fn zero_sized(ty: Ty<'tcx>) -> Self {
+ let cv = ConstValue::ZeroSized;
+ Self::Val(cv, ty)
+ }
+
+ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
+ let ty = tcx.types.usize;
+ Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
+ }
+
+ #[inline]
+ pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
+ let val = ConstValue::Scalar(s);
+ Self::Val(val, ty)
+ }
+
+ /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
+ /// converted to a constant, everything else becomes `Unevaluated`.
+ pub fn from_anon_const(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Self {
+ Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
+ }
+
+ #[instrument(skip(tcx), level = "debug")]
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let body_id = match tcx.hir().get(hir_id) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def_id.to_def_id()),
+ "from_inline_const can only process anonymous constants"
+ ),
+ };
+ let expr = &tcx.hir().body(body_id).value;
+ let ty = tcx.typeck(def_id).node_type(hir_id);
+
+ let lit_input = match expr.kind {
+ hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+ hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
+ hir::ExprKind::Lit(ref lit) => {
+ Some(LitToConstInput { lit: &lit.node, ty, neg: true })
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(lit_input) = lit_input {
+ // If an error occurred, ignore that it's a literal and leave reporting the error up to
+ // mir.
+ match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
+ Ok(c) => return c,
+ Err(_) => {}
+ }
+ }
+
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+ let uneval_const = tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: ty::WithOptConstParam::unknown(def_id).to_global(),
+ substs,
+ promoted: None,
+ }),
+ ty,
+ });
+ debug!(?uneval_const);
+ debug_assert!(!uneval_const.has_free_regions());
+
+ Self::Ty(uneval_const)
+ }
+
+ #[instrument(skip(tcx), level = "debug")]
+ fn from_opt_const_arg_anon_const(
+ tcx: TyCtxt<'tcx>,
+ def: ty::WithOptConstParam<LocalDefId>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Self {
+ let body_id = match tcx.hir().get_by_def_id(def.did) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def.did.to_def_id()),
+ "from_anon_const can only process anonymous constants"
+ ),
+ };
+
+ let expr = &tcx.hir().body(body_id).value;
+ debug!(?expr);
+
+ // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+ // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+ let expr = match &expr.kind {
+ hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+ block.expr.as_ref().unwrap()
+ }
+ _ => expr,
+ };
+ debug!("expr.kind: {:?}", expr.kind);
+
+ let ty = tcx.type_of(def.def_id_for_type_of());
+ debug!(?ty);
+
+ // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
+ // does not provide the parents generics to anonymous constants. We still allow generic const
+ // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
+ // ever try to substitute the generic parameters in their bodies.
+ //
+ // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
+ // cause issues if we were to remove that special-case and try to evaluate the constant instead.
+ use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
+ match expr.kind {
+ ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
+ // Find the name and index of the const parameter by indexing the generics of
+ // the parent item and construct a `ParamConst`.
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let item_id = tcx.hir().get_parent_node(hir_id);
+ let item_def_id = tcx.hir().local_def_id(item_id);
+ let generics = tcx.generics_of(item_def_id.to_def_id());
+ let index = generics.param_def_id_to_index[&def_id];
+ let name = tcx.hir().name(hir_id);
+ let ty_const = tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+ ty,
+ });
+ debug!(?ty_const);
+
+ return Self::Ty(ty_const);
+ }
+ _ => {}
+ }
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
+ if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
+ InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
+ } else {
+ tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
+ }
+ } else {
+ tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
+ };
+ debug!(?parent_substs);
+
+ let did = def.did.to_def_id();
+ let child_substs = InternalSubsts::identity_for_item(tcx, did);
+ let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter()));
+ debug!(?substs);
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let span = tcx.hir().span(hir_id);
+ let uneval = ty::Unevaluated::new(def.to_global(), substs);
+ debug!(?span, ?param_env);
+
+ match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
+ Ok(val) => {
+ debug!("evaluated const value: {:?}", val);
+ Self::Val(val, ty)
+ }
+ Err(_) => {
+ debug!("error encountered during evaluation");
+ // Error was handled in `const_eval_resolve`. Here we just create a
+ // new unevaluated const and error hard later in codegen
+ let ty_const = tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: def.to_global(),
+ substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+ promoted: None,
+ }),
+ ty,
+ });
+ debug!(?ty_const);
+
+ Self::Ty(ty_const)
+ }
+ }
+ }
+
+ pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+ match c.kind() {
+ ty::ConstKind::Value(valtree) => {
+ let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
+ Self::Val(const_val, c.ty())
+ }
+ _ => Self::Ty(c),
+ }
+ }
+}
+
+/// 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:
+///
+/// ```ignore (illustrative)
+/// 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, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct UserTypeProjections {
+ pub contents: Vec<(UserTypeProjection, Span)>,
+}
+
+impl<'tcx> UserTypeProjections {
+ pub fn none() -> Self {
+ UserTypeProjections { contents: vec![] }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.contents.is_empty()
+ }
+
+ 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.into_iter().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: u64, to: u64) -> 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: AdtDef<'tcx>, 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 projections 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, TyEncodable, TyDecodable, Hash, 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: u64, to: u64) -> 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: AdtDef<'_>,
+ variant_index: VariantIdx,
+ field: Field,
+ ) -> Self {
+ self.projs.push(ProjectionElem::Downcast(
+ Some(adt_def.variant(variant_index).name),
+ variant_index,
+ ));
+ self.projs.push(ProjectionElem::Field(field, ()));
+ self
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! { ProjectionKind, }
+
+impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(UserTypeProjection {
+ base: self.base.try_fold_with(folder)?,
+ projs: self.projs.try_fold_with(folder)?,
+ })
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for UserTypeProjection {
+ fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
+ 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 {
+ match self.ty().kind() {
+ ty::FnDef(..) => {}
+ _ => write!(fmt, "const ")?,
+ }
+ Display::fmt(&self.literal, fmt)
+ }
+}
+
+impl<'tcx> Display for ConstantKind<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ match *self {
+ ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
+ ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true),
+ }
+ }
+}
+
+fn pretty_print_const<'tcx>(
+ c: ty::Const<'tcx>,
+ fmt: &mut Formatter<'_>,
+ print_types: bool,
+) -> fmt::Result {
+ use crate::ty::print::PrettyPrinter;
+ ty::tls::with(|tcx| {
+ let literal = tcx.lift(c).unwrap();
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let cx = cx.pretty_print_const(literal, print_types)?;
+ fmt.write_str(&cx.into_buffer())?;
+ Ok(())
+ })
+}
+
+fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result {
+ fmt.write_str("b\"")?;
+ for &c in byte_str {
+ for e in std::ascii::escape_default(c) {
+ fmt.write_char(e as char)?;
+ }
+ }
+ fmt.write_str("\"")?;
+
+ Ok(())
+}
+
+fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result {
+ let mut first = true;
+ for elem in elems {
+ if !first {
+ fmt.write_str(", ")?;
+ }
+ fmt.write_str(&format!("{}", elem))?;
+ first = false;
+ }
+ Ok(())
+}
+
+// FIXME: Move that into `mir/pretty.rs`.
+fn pretty_print_const_value<'tcx>(
+ ct: ConstValue<'tcx>,
+ ty: Ty<'tcx>,
+ fmt: &mut Formatter<'_>,
+ print_ty: bool,
+) -> fmt::Result {
+ use crate::ty::print::PrettyPrinter;
+
+ ty::tls::with(|tcx| {
+ let ct = tcx.lift(ct).unwrap();
+ let ty = tcx.lift(ty).unwrap();
+
+ if tcx.sess.verbose() {
+ fmt.write_str(&format!("ConstValue({:?}: {})", ct, ty))?;
+ return Ok(());
+ }
+
+ let u8_type = tcx.types.u8;
+ match (ct, ty.kind()) {
+ // Byte/string slices, printed as (byte) string literals.
+ (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => {
+ match inner.kind() {
+ ty::Slice(t) => {
+ if *t == u8_type {
+ // 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.
+ let byte_str = data
+ .inner()
+ .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ pretty_print_byte_str(fmt, byte_str)?;
+ return Ok(());
+ }
+ }
+ ty::Str => {
+ // 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
+ .inner()
+ .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ fmt.write_str(&format!("{:?}", String::from_utf8_lossy(slice)))?;
+ return Ok(());
+ }
+ _ => {}
+ }
+ }
+ (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
+ let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap();
+ // cast is ok because we already checked for pointer size (32 or 64 bit) above
+ let range = AllocRange { start: offset, size: Size::from_bytes(n) };
+ let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap();
+ fmt.write_str("*")?;
+ pretty_print_byte_str(fmt, byte_str)?;
+ return Ok(());
+ }
+ // Aggregates, printed as array/tuple/struct/variant construction syntax.
+ //
+ // NB: the `has_param_types_or_consts` check ensures that we can use
+ // the `destructure_const` query with an empty `ty::ParamEnv` without
+ // introducing ICEs (e.g. via `layout_of`) from missing bounds.
+ // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
+ // to be able to destructure the tuple into `(0u8, *mut T)
+ //
+ // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
+ // correct `ty::ParamEnv` to allow printing *all* constant values.
+ (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
+ let ct = tcx.lift(ct).unwrap();
+ let ty = tcx.lift(ty).unwrap();
+ if let Some(contents) = tcx.try_destructure_mir_constant(
+ ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)),
+ ) {
+ let fields = contents.fields.iter().copied().collect::<Vec<_>>();
+ match *ty.kind() {
+ ty::Array(..) => {
+ fmt.write_str("[")?;
+ comma_sep(fmt, fields)?;
+ fmt.write_str("]")?;
+ }
+ ty::Tuple(..) => {
+ fmt.write_str("(")?;
+ comma_sep(fmt, fields)?;
+ if contents.fields.len() == 1 {
+ fmt.write_str(",")?;
+ }
+ fmt.write_str(")")?;
+ }
+ ty::Adt(def, _) if def.variants().is_empty() => {
+ fmt.write_str(&format!("{{unreachable(): {}}}", ty))?;
+ }
+ ty::Adt(def, substs) => {
+ let variant_idx = contents
+ .variant
+ .expect("destructed mir constant of adt without variant idx");
+ let variant_def = &def.variant(variant_idx);
+ let substs = tcx.lift(substs).unwrap();
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let cx = cx.print_value_path(variant_def.def_id, substs)?;
+ fmt.write_str(&cx.into_buffer())?;
+
+ match variant_def.ctor_kind {
+ CtorKind::Const => {}
+ CtorKind::Fn => {
+ fmt.write_str("(")?;
+ comma_sep(fmt, fields)?;
+ fmt.write_str(")")?;
+ }
+ CtorKind::Fictive => {
+ fmt.write_str(" {{ ")?;
+ let mut first = true;
+ for (field_def, field) in iter::zip(&variant_def.fields, fields)
+ {
+ if !first {
+ fmt.write_str(", ")?;
+ }
+ fmt.write_str(&format!("{}: {}", field_def.name, field))?;
+ first = false;
+ }
+ fmt.write_str(" }}")?;
+ }
+ }
+ }
+ _ => unreachable!(),
+ }
+ return Ok(());
+ } else {
+ // Fall back to debug pretty printing for invalid constants.
+ fmt.write_str(&format!("{:?}", ct))?;
+ if print_ty {
+ fmt.write_str(&format!(": {}", ty))?;
+ }
+ return Ok(());
+ };
+ }
+ (ConstValue::Scalar(scalar), _) => {
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let ty = tcx.lift(ty).unwrap();
+ cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?;
+ fmt.write_str(&cx.into_buffer())?;
+ return Ok(());
+ }
+ (ConstValue::ZeroSized, ty::FnDef(d, s)) => {
+ let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+ cx.print_alloc_ids = true;
+ let cx = cx.print_value_path(*d, s)?;
+ fmt.write_str(&cx.into_buffer())?;
+ return Ok(());
+ }
+ // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
+ // their fields instead of just dumping the memory.
+ _ => {}
+ }
+ // fallback
+ fmt.write_str(&format!("{:?}", ct))?;
+ if print_ty {
+ fmt.write_str(&format!(": {}", ty))?;
+ }
+ Ok(())
+ })
+}
+
+/// `Location` represents the position of the start of the statement; or, if
+/// `statement_index` equals the number of statements, then the start of the
+/// terminator.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)]
+pub struct Location {
+ /// The block that the location is within.
+ pub block: BasicBlock,
+
+ 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: &Body<'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;
+ }
+
+ let predecessors = body.basic_blocks.predecessors();
+
+ // If we're in another block, then we want to check that block is a predecessor of `other`.
+ let mut queue: Vec<BasicBlock> = predecessors[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 its predecessors.
+ if visited.insert(block) {
+ queue.extend(predecessors[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)
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
new file mode 100644
index 000000000..21ae121e1
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -0,0 +1,527 @@
+use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
+use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
+use rustc_attr::InlineAttr;
+use rustc_data_structures::base_n;
+use rustc_data_structures::fingerprint::Fingerprint;
+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::ItemId;
+use rustc_index::vec::Idx;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_session::config::OptLevel;
+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, HashStable)]
+pub enum MonoItem<'tcx> {
+ Fn(Instance<'tcx>),
+ Static(DefId),
+ GlobalAsm(ItemId),
+}
+
+impl<'tcx> MonoItem<'tcx> {
+ /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims).
+ pub fn is_user_defined(&self) -> bool {
+ match *self {
+ MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)),
+ MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true,
+ }
+ }
+
+ 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<'tcx> {
+ match *self {
+ MonoItem::Fn(instance) => tcx.symbol_name(instance),
+ MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)),
+ MonoItem::GlobalAsm(item_id) => {
+ SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id))
+ }
+ }
+ }
+
+ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
+ let generate_cgu_internal_copies = tcx
+ .sess
+ .opts
+ .unstable_opts
+ .inline_in_all_cgus
+ .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
+ && !tcx.sess.link_dead_code();
+
+ match *self {
+ MonoItem::Fn(ref instance) => {
+ let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
+ // If this function isn't inlined or otherwise has an extern
+ // indicator, then we'll be creating a globally shared version.
+ if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
+ || !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.subst_and_check_impossible_predicates((def_id, &substs))
+ }
+
+ pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
+ match *self {
+ MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(),
+ MonoItem::Static(def_id) => def_id.as_local(),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.def_id),
+ }
+ .map(|def_id| tcx.def_span(def_id))
+ }
+
+ // Only used by rustc_codegen_cranelift
+ pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
+ crate::dep_graph::make_compile_mono_item(tcx, self)
+ }
+
+ /// Returns the item's `CrateNum`
+ pub fn krate(&self) -> CrateNum {
+ match self {
+ MonoItem::Fn(ref instance) => instance.def_id().krate,
+ MonoItem::Static(def_id) => def_id.krate,
+ MonoItem::GlobalAsm(..) => LOCAL_CRATE,
+ }
+ }
+}
+
+impl<'tcx> fmt::Display for MonoItem<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ MonoItem::Fn(instance) => write!(f, "fn {}", instance),
+ MonoItem::Static(def_id) => {
+ write!(f, "static {}", Instance::new(def_id, InternalSubsts::empty()))
+ }
+ MonoItem::GlobalAsm(..) => write!(f, "global_asm"),
+ }
+ }
+}
+
+#[derive(Debug)]
+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>,
+ primary: bool,
+ /// True if this is CGU is used to hold code coverage information for dead code,
+ /// false otherwise.
+ is_code_coverage_dead_code_cgu: bool,
+}
+
+/// Specifies the linkage type for a `MonoItem`.
+///
+/// See <https://llvm.org/docs/LangRef.html#linkage-types> for more details about these variants.
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, 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> {
+ #[inline]
+ pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
+ CodegenUnit {
+ name,
+ items: Default::default(),
+ size_estimate: None,
+ primary: false,
+ is_code_coverage_dead_code_cgu: false,
+ }
+ }
+
+ pub fn name(&self) -> Symbol {
+ self.name
+ }
+
+ pub fn set_name(&mut self, name: Symbol) {
+ self.name = name;
+ }
+
+ pub fn is_primary(&self) -> bool {
+ self.primary
+ }
+
+ pub fn make_primary(&mut self) {
+ self.primary = true;
+ }
+
+ 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 is_code_coverage_dead_code_cgu(&self) -> bool {
+ self.is_code_coverage_dead_code_cgu
+ }
+
+ /// Marks this CGU as the one used to contain code coverage information for dead code.
+ pub fn make_code_coverage_dead_code_cgu(&mut self) {
+ self.is_code_coverage_dead_code_cgu = true;
+ }
+
+ 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());
+ }
+
+ #[inline]
+ 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 previous_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<'tcx>(Option<usize>, SymbolName<'tcx>);
+
+ fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'tcx> {
+ 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) => def.did.as_local().map(Idx::index),
+ InstanceDef::VTableShim(..)
+ | InstanceDef::ReifyShim(..)
+ | InstanceDef::Intrinsic(..)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::Virtual(..)
+ | InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::CloneShim(..) => None,
+ }
+ }
+ MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.index()),
+ },
+ 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 {
+ crate::dep_graph::make_compile_codegen_unit(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: _,
+ primary: _,
+ is_code_coverage_dead_code_cgu,
+ } = *self;
+
+ name.hash_stable(hcx, hasher);
+ is_code_coverage_dead_code_cgu.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<'tcx> 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:
+ ///
+ /// ```text
+ /// <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.unstable_opts.human_readable_cgu_names {
+ cgu_name
+ } else {
+ Symbol::intern(&CodegenUnit::mangle_name(cgu_name.as_str()))
+ }
+ }
+
+ /// 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_stable_crate_id = tcx.sess.local_stable_crate_id();
+ format!(
+ "-in-{}.{:08x}",
+ tcx.crate_name(LOCAL_CRATE),
+ local_stable_crate_id.to_u64() as u32,
+ )
+ } else {
+ String::new()
+ };
+
+ let stable_crate_id = tcx.sess.local_stable_crate_id();
+ format!(
+ "{}.{:08x}{}",
+ tcx.crate_name(cnum),
+ stable_crate_id.to_u64() as u32,
+ 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/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
new file mode 100644
index 000000000..15496842d
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/patch.rs
@@ -0,0 +1,196 @@
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::*;
+use rustc_middle::ty::Ty;
+use rustc_span::Span;
+
+/// This struct represents a patch to MIR, which can add
+/// new statements and basic blocks and patch over block
+/// terminators.
+pub struct MirPatch<'tcx> {
+ patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
+ new_blocks: Vec<BasicBlockData<'tcx>>,
+ new_statements: Vec<(Location, StatementKind<'tcx>)>,
+ new_locals: Vec<LocalDecl<'tcx>>,
+ resume_block: Option<BasicBlock>,
+ body_span: Span,
+ next_local: usize,
+}
+
+impl<'tcx> MirPatch<'tcx> {
+ pub fn new(body: &Body<'tcx>) -> Self {
+ let mut result = MirPatch {
+ patch_map: IndexVec::from_elem(None, body.basic_blocks()),
+ new_blocks: vec![],
+ new_statements: vec![],
+ new_locals: vec![],
+ next_local: body.local_decls.len(),
+ resume_block: None,
+ body_span: body.span,
+ };
+
+ // Check if we already have a resume block
+ for (bb, block) in body.basic_blocks().iter_enumerated() {
+ if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
+ result.resume_block = Some(bb);
+ break;
+ }
+ }
+
+ result
+ }
+
+ pub fn resume_block(&mut self) -> BasicBlock {
+ if let Some(bb) = self.resume_block {
+ return bb;
+ }
+
+ let bb = self.new_block(BasicBlockData {
+ statements: vec![],
+ terminator: Some(Terminator {
+ source_info: SourceInfo::outermost(self.body_span),
+ kind: TerminatorKind::Resume,
+ }),
+ is_cleanup: true,
+ });
+ self.resume_block = Some(bb);
+ bb
+ }
+
+ pub fn is_patched(&self, bb: BasicBlock) -> bool {
+ self.patch_map[bb].is_some()
+ }
+
+ pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location {
+ let offset = match bb.index().checked_sub(body.basic_blocks().len()) {
+ Some(index) => self.new_blocks[index].statements.len(),
+ None => body[bb].statements.len(),
+ };
+ Location { block: bb, statement_index: offset }
+ }
+
+ pub fn new_local_with_info(
+ &mut self,
+ ty: Ty<'tcx>,
+ span: Span,
+ local_info: Option<Box<LocalInfo<'tcx>>>,
+ ) -> Local {
+ let index = self.next_local;
+ self.next_local += 1;
+ let mut new_decl = LocalDecl::new(ty, span);
+ new_decl.local_info = local_info;
+ self.new_locals.push(new_decl);
+ Local::new(index as usize)
+ }
+
+ pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
+ self.new_local_with_info(ty, span, None)
+ }
+
+ pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
+ let index = self.next_local;
+ self.next_local += 1;
+ self.new_locals.push(LocalDecl::new(ty, span).internal());
+ Local::new(index as usize)
+ }
+
+ pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
+ let block = BasicBlock::new(self.patch_map.len());
+ debug!("MirPatch: new_block: {:?}: {:?}", block, data);
+ self.new_blocks.push(data);
+ self.patch_map.push(None);
+ block
+ }
+
+ pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
+ assert!(self.patch_map[block].is_none());
+ debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
+ self.patch_map[block] = Some(new);
+ }
+
+ pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) {
+ debug!("MirPatch: add_statement({:?}, {:?})", loc, stmt);
+ self.new_statements.push((loc, stmt));
+ }
+
+ pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
+ self.add_statement(loc, StatementKind::Assign(Box::new((place, rv))));
+ }
+
+ pub fn apply(self, body: &mut Body<'tcx>) {
+ debug!(
+ "MirPatch: {:?} new temps, starting from index {}: {:?}",
+ self.new_locals.len(),
+ body.local_decls.len(),
+ self.new_locals
+ );
+ debug!(
+ "MirPatch: {} new blocks, starting from index {}",
+ self.new_blocks.len(),
+ body.basic_blocks().len()
+ );
+ let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
+ body.basic_blocks.as_mut_preserves_cfg()
+ } else {
+ body.basic_blocks.as_mut()
+ };
+ bbs.extend(self.new_blocks);
+ body.local_decls.extend(self.new_locals);
+ for (src, patch) in self.patch_map.into_iter_enumerated() {
+ if let Some(patch) = patch {
+ debug!("MirPatch: patching block {:?}", src);
+ bbs[src].terminator_mut().kind = patch;
+ }
+ }
+
+ let mut new_statements = self.new_statements;
+ new_statements.sort_by_key(|s| s.0);
+
+ let mut delta = 0;
+ let mut last_bb = START_BLOCK;
+ let mut stmts_and_targets: Vec<(Statement<'_>, BasicBlock)> = Vec::new();
+ for (mut loc, stmt) in new_statements {
+ if loc.block != last_bb {
+ delta = 0;
+ last_bb = loc.block;
+ }
+ debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
+ loc.statement_index += delta;
+ let source_info = Self::source_info_for_index(&body[loc.block], loc);
+
+ // For mir-opt `Derefer` to work in all cases we need to
+ // get terminator's targets and apply the statement to all of them.
+ if loc.statement_index > body[loc.block].statements.len() {
+ let term = body[loc.block].terminator();
+ for i in term.successors() {
+ stmts_and_targets.push((Statement { source_info, kind: stmt.clone() }, i));
+ }
+ delta += 1;
+ continue;
+ }
+
+ body[loc.block]
+ .statements
+ .insert(loc.statement_index, Statement { source_info, kind: stmt });
+ delta += 1;
+ }
+
+ for (stmt, target) in stmts_and_targets.into_iter().rev() {
+ body[target].statements.insert(0, stmt);
+ }
+ }
+
+ pub fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo {
+ match data.statements.get(loc.statement_index) {
+ Some(stmt) => stmt.source_info,
+ None => data.terminator().source_info,
+ }
+ }
+
+ pub fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo {
+ let data = match loc.block.index().checked_sub(body.basic_blocks().len()) {
+ Some(new) => &self.new_blocks[new],
+ None => &body[loc.block],
+ };
+ Self::source_info_for_index(data, loc)
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
new file mode 100644
index 000000000..5f1fadaf3
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/predecessors.rs
@@ -0,0 +1,78 @@
+//! Lazily compute the reverse control-flow graph for the MIR.
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_index::vec::IndexVec;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use smallvec::SmallVec;
+
+use crate::mir::{BasicBlock, BasicBlockData};
+
+// Typically 95%+ of basic blocks have 4 or fewer predecessors.
+pub type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
+
+#[derive(Clone, Debug)]
+pub(super) struct PredecessorCache {
+ cache: OnceCell<Predecessors>,
+}
+
+impl PredecessorCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ PredecessorCache { cache: OnceCell::new() }
+ }
+
+ /// Invalidates the predecessor cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ // Invalidating the predecessor cache requires mutating the MIR, which in turn requires a
+ // unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
+ // callers of `invalidate` have a unique reference to the MIR and thus to the predecessor
+ // cache. This means we never need to do synchronization when `invalidate` is called, we can
+ // simply reinitialize the `OnceCell`.
+ self.cache = OnceCell::new();
+ }
+
+ /// Returns the predecessor graph for this MIR.
+ #[inline]
+ pub(super) fn compute(
+ &self,
+ basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
+ ) -> &Predecessors {
+ self.cache.get_or_init(|| {
+ let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks);
+ for (bb, data) in basic_blocks.iter_enumerated() {
+ if let Some(term) = &data.terminator {
+ for succ in term.successors() {
+ preds[succ].push(bb);
+ }
+ }
+ }
+
+ preds
+ })
+ }
+}
+
+impl<S: Encoder> Encodable<S> for PredecessorCache {
+ #[inline]
+ fn encode(&self, _s: &mut S) {}
+}
+
+impl<D: Decoder> Decodable<D> for PredecessorCache {
+ #[inline]
+ fn decode(_: &mut D) -> Self {
+ Self::new()
+ }
+}
+
+impl<CTX> HashStable<CTX> for PredecessorCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ PredecessorCache,
+}
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
new file mode 100644
index 000000000..0ce41337b
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -0,0 +1,1067 @@
+use std::collections::BTreeSet;
+use std::fmt::Display;
+use std::fmt::Write as _;
+use std::fs;
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+
+use super::graphviz::write_mir_fn_graphviz;
+use super::spanview::write_mir_fn_spanview;
+use either::Either;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::Idx;
+use rustc_middle::mir::interpret::{
+ read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc, Pointer,
+ Provenance,
+};
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::MirSource;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_target::abi::Size;
+
+const INDENT: &str = " ";
+/// Alignment for lining up comments following MIR statements
+pub(crate) const ALIGN: usize = 40;
+
+/// An indication of where we are in the control flow graph. Used for printing
+/// extra information in `dump_mir`
+pub enum PassWhere {
+ /// We have not started dumping the control flow graph, but we are about to.
+ BeforeCFG,
+
+ /// We just finished dumping the control flow graph. This is right before EOF
+ AfterCFG,
+
+ /// We are about to start dumping the given basic block.
+ BeforeBlock(BasicBlock),
+
+ /// We are just about to dump the given statement or terminator.
+ BeforeLocation(Location),
+
+ /// We just dumped the given statement or terminator.
+ AfterLocation(Location),
+
+ /// We just dumped the terminator for a block but not the closing `}`.
+ AfterTerminator(BasicBlock),
+}
+
+/// If the session is properly configured, dumps a human-readable
+/// representation of the mir into:
+///
+/// ```text
+/// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator>
+/// ```
+///
+/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
+/// where `<filter>` takes the following forms:
+///
+/// - `all` -- dump MIR for all fns, all passes, all everything
+/// - a filter defined by a set of substrings combined with `&` and `|`
+/// (`&` has higher precedence). At least one of the `|`-separated groups
+/// must match; an `|`-separated group matches if all of its `&`-separated
+/// substrings are matched.
+///
+/// Example:
+///
+/// - `nll` == match if `nll` appears in the name
+/// - `foo & nll` == match if `foo` and `nll` both appear in the name
+/// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name
+/// or `typeck` appears in the name.
+/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name
+/// or `typeck` and `bar` both appear in the name.
+#[inline]
+pub fn dump_mir<'tcx, F>(
+ tcx: TyCtxt<'tcx>,
+ pass_num: Option<&dyn Display>,
+ pass_name: &str,
+ disambiguator: &dyn Display,
+ body: &Body<'tcx>,
+ extra_data: F,
+) where
+ F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+{
+ if !dump_enabled(tcx, pass_name, body.source.def_id()) {
+ return;
+ }
+
+ dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data);
+}
+
+pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool {
+ let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir else {
+ return false;
+ };
+ // see notes on #41697 below
+ let node_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(def_id));
+ filters.split('|').any(|or_filter| {
+ or_filter.split('&').all(|and_filter| {
+ let and_filter_trimmed = and_filter.trim();
+ and_filter_trimmed == "all"
+ || pass_name.contains(and_filter_trimmed)
+ || node_path.contains(and_filter_trimmed)
+ })
+ })
+}
+
+// #41697 -- we use `with_forced_impl_filename_line()` because
+// `def_path_str()` would otherwise trigger `type_of`, and this can
+// run while we are already attempting to evaluate `type_of`.
+
+fn dump_matched_mir_node<'tcx, F>(
+ tcx: TyCtxt<'tcx>,
+ pass_num: Option<&dyn Display>,
+ pass_name: &str,
+ disambiguator: &dyn Display,
+ body: &Body<'tcx>,
+ mut extra_data: F,
+) where
+ F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+{
+ let _: io::Result<()> = try {
+ let mut file =
+ create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body.source)?;
+ // see notes on #41697 above
+ let def_path =
+ ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
+ write!(file, "// MIR for `{}", def_path)?;
+ match body.source.promoted {
+ None => write!(file, "`")?,
+ Some(promoted) => write!(file, "::{:?}`", promoted)?,
+ }
+ writeln!(file, " {} {}", disambiguator, pass_name)?;
+ if let Some(ref layout) = body.generator_layout() {
+ writeln!(file, "/* generator_layout = {:#?} */", layout)?;
+ }
+ writeln!(file)?;
+ extra_data(PassWhere::BeforeCFG, &mut file)?;
+ write_user_type_annotations(tcx, body, &mut file)?;
+ write_mir_fn(tcx, body, &mut extra_data, &mut file)?;
+ extra_data(PassWhere::AfterCFG, &mut file)?;
+ };
+
+ if tcx.sess.opts.unstable_opts.dump_mir_graphviz {
+ let _: io::Result<()> = try {
+ let mut file =
+ create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?;
+ write_mir_fn_graphviz(tcx, body, false, &mut file)?;
+ };
+ }
+
+ if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview {
+ let _: io::Result<()> = try {
+ let file_basename =
+ dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source);
+ let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?;
+ if body.source.def_id().is_local() {
+ write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?;
+ }
+ };
+ }
+}
+
+/// Returns the file basename portion (without extension) of a filename path
+/// where we should dump a MIR representation output files.
+fn dump_file_basename<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ pass_num: Option<&dyn Display>,
+ pass_name: &str,
+ disambiguator: &dyn Display,
+ source: MirSource<'tcx>,
+) -> String {
+ let promotion_id = match source.promoted {
+ Some(id) => format!("-{:?}", id),
+ None => String::new(),
+ };
+
+ let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number {
+ String::new()
+ } else {
+ match pass_num {
+ None => ".-------".to_string(),
+ Some(pass_num) => format!(".{}", pass_num),
+ }
+ };
+
+ let crate_name = tcx.crate_name(source.def_id().krate);
+ let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate();
+ // All drop shims have the same DefId, so we have to add the type
+ // to get unique file names.
+ let shim_disambiguator = match source.instance {
+ ty::InstanceDef::DropGlue(_, Some(ty)) => {
+ // Unfortunately, pretty-printed typed are not very filename-friendly.
+ // We dome some filtering.
+ let mut s = ".".to_owned();
+ s.extend(ty.to_string().chars().filter_map(|c| match c {
+ ' ' => None,
+ ':' | '<' | '>' => Some('_'),
+ c => Some(c),
+ }));
+ s
+ }
+ _ => String::new(),
+ };
+
+ format!(
+ "{}.{}{}{}{}.{}.{}",
+ crate_name, item_name, shim_disambiguator, promotion_id, pass_num, pass_name, disambiguator,
+ )
+}
+
+/// Returns the path to the filename where we should dump a given MIR.
+/// Also used by other bits of code (e.g., NLL inference) that dump
+/// graphviz data or other things.
+fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf {
+ let mut file_path = PathBuf::new();
+ file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir));
+
+ let file_name = format!("{}.{}", basename, extension,);
+
+ file_path.push(&file_name);
+
+ file_path
+}
+
+/// Attempts to open the MIR dump file with the given name and extension.
+fn create_dump_file_with_basename(
+ tcx: TyCtxt<'_>,
+ file_basename: &str,
+ extension: &str,
+) -> io::Result<io::BufWriter<fs::File>> {
+ let file_path = dump_path(tcx, file_basename, extension);
+ if let Some(parent) = file_path.parent() {
+ fs::create_dir_all(parent).map_err(|e| {
+ io::Error::new(
+ e.kind(),
+ format!("IO error creating MIR dump directory: {:?}; {}", parent, e),
+ )
+ })?;
+ }
+ Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| {
+ io::Error::new(e.kind(), format!("IO error creating MIR dump file: {:?}; {}", file_path, e))
+ })?))
+}
+
+/// Attempts to open a file where we should dump a given MIR or other
+/// bit of MIR-related data. Used by `mir-dump`, but also by other
+/// bits of code (e.g., NLL inference) that dump graphviz data or
+/// other things, and hence takes the extension as an argument.
+pub fn create_dump_file<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ extension: &str,
+ pass_num: Option<&dyn Display>,
+ pass_name: &str,
+ disambiguator: &dyn Display,
+ source: MirSource<'tcx>,
+) -> io::Result<io::BufWriter<fs::File>> {
+ create_dump_file_with_basename(
+ tcx,
+ &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source),
+ extension,
+ )
+}
+
+/// Write out a human-readable textual representation for the given MIR.
+pub fn write_mir_pretty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ single: Option<DefId>,
+ w: &mut dyn Write,
+) -> io::Result<()> {
+ writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
+ writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;
+
+ let mut first = true;
+ for def_id in dump_mir_def_ids(tcx, single) {
+ if first {
+ first = false;
+ } else {
+ // Put empty lines between all items
+ writeln!(w)?;
+ }
+
+ let render_body = |w: &mut dyn Write, body| -> io::Result<()> {
+ write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
+
+ for body in tcx.promoted_mir(def_id) {
+ writeln!(w)?;
+ write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
+ }
+ Ok(())
+ };
+
+ // For `const fn` we want to render both the optimized MIR and the MIR for ctfe.
+ if tcx.is_const_fn_raw(def_id) {
+ render_body(w, tcx.optimized_mir(def_id))?;
+ writeln!(w)?;
+ writeln!(w, "// MIR FOR CTFE")?;
+ // Do not use `render_body`, as that would render the promoteds again, but these
+ // are shared between mir_for_ctfe and optimized_mir
+ write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
+ } else {
+ let instance_mir =
+ tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)));
+ render_body(w, instance_mir)?;
+ }
+ }
+ Ok(())
+}
+
+/// Write out a human-readable textual representation for the given function.
+pub fn write_mir_fn<'tcx, F>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
+ extra_data: &mut F,
+ w: &mut dyn Write,
+) -> io::Result<()>
+where
+ F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+{
+ write_mir_intro(tcx, body, w)?;
+ for block in body.basic_blocks().indices() {
+ extra_data(PassWhere::BeforeBlock(block), w)?;
+ write_basic_block(tcx, block, body, extra_data, w)?;
+ if block.index() + 1 != body.basic_blocks().len() {
+ writeln!(w)?;
+ }
+ }
+
+ writeln!(w, "}}")?;
+
+ write_allocations(tcx, body, w)?;
+
+ Ok(())
+}
+
+/// Write out a human-readable textual representation for the given basic block.
+pub fn write_basic_block<'tcx, F>(
+ tcx: TyCtxt<'tcx>,
+ block: BasicBlock,
+ body: &Body<'tcx>,
+ extra_data: &mut F,
+ w: &mut dyn Write,
+) -> io::Result<()>
+where
+ F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
+{
+ let data = &body[block];
+
+ // Basic block label at the top.
+ let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" };
+ writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?;
+
+ // List of statements in the middle.
+ let mut current_location = Location { block, statement_index: 0 };
+ for statement in &data.statements {
+ extra_data(PassWhere::BeforeLocation(current_location), w)?;
+ let indented_body = format!("{0}{0}{1:?};", INDENT, statement);
+ writeln!(
+ w,
+ "{:A$} // {}{}",
+ indented_body,
+ if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() },
+ comment(tcx, statement.source_info, body.span),
+ A = ALIGN,
+ )?;
+
+ write_extra(tcx, w, |visitor| {
+ visitor.visit_statement(statement, current_location);
+ })?;
+
+ extra_data(PassWhere::AfterLocation(current_location), w)?;
+
+ current_location.statement_index += 1;
+ }
+
+ // Terminator at the bottom.
+ extra_data(PassWhere::BeforeLocation(current_location), w)?;
+ let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
+ writeln!(
+ w,
+ "{:A$} // {}{}",
+ indented_terminator,
+ if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() },
+ comment(tcx, data.terminator().source_info, body.span),
+ A = ALIGN,
+ )?;
+
+ write_extra(tcx, w, |visitor| {
+ visitor.visit_terminator(data.terminator(), current_location);
+ })?;
+
+ extra_data(PassWhere::AfterLocation(current_location), w)?;
+ extra_data(PassWhere::AfterTerminator(block), w)?;
+
+ writeln!(w, "{}}}", INDENT)
+}
+
+/// After we print the main statement, we sometimes dump extra
+/// information. There's often a lot of little things "nuzzled up" in
+/// a statement.
+fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: F) -> io::Result<()>
+where
+ F: FnMut(&mut ExtraComments<'tcx>),
+{
+ let mut extra_comments = ExtraComments { tcx, comments: vec![] };
+ visit_op(&mut extra_comments);
+ for comment in extra_comments.comments {
+ writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?;
+ }
+ Ok(())
+}
+
+struct ExtraComments<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ comments: Vec<String>,
+}
+
+impl<'tcx> ExtraComments<'tcx> {
+ fn push(&mut self, lines: &str) {
+ for line in lines.split('\n') {
+ self.comments.push(line.to_string());
+ }
+ }
+}
+
+fn use_verbose<'tcx>(ty: Ty<'tcx>, fn_def: bool) -> bool {
+ match *ty.kind() {
+ ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false,
+ // Unit type
+ ty::Tuple(g_args) if g_args.is_empty() => false,
+ ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(g_arg, fn_def)),
+ ty::Array(ty, _) => use_verbose(ty, fn_def),
+ ty::FnDef(..) => fn_def,
+ _ => true,
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
+ fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
+ let Constant { span, user_ty, literal } = constant;
+ if use_verbose(literal.ty(), true) {
+ self.push("mir::Constant");
+ self.push(&format!(
+ "+ span: {}",
+ self.tcx.sess.source_map().span_to_embeddable_string(*span)
+ ));
+ if let Some(user_ty) = user_ty {
+ self.push(&format!("+ user_ty: {:?}", user_ty));
+ }
+
+ // FIXME: this is a poor version of `pretty_print_const_value`.
+ let fmt_val = |val: &ConstValue<'tcx>| match val {
+ ConstValue::ZeroSized => format!("<ZST>"),
+ ConstValue::Scalar(s) => format!("Scalar({:?})", s),
+ ConstValue::Slice { .. } => format!("Slice(..)"),
+ ConstValue::ByRef { .. } => format!("ByRef(..)"),
+ };
+
+ let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
+ ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf),
+ ty::ValTree::Branch(_) => format!("ValTree::Branch(..)"),
+ };
+
+ let val = match literal {
+ ConstantKind::Ty(ct) => match ct.kind() {
+ ty::ConstKind::Param(p) => format!("Param({})", p),
+ ty::ConstKind::Unevaluated(uv) => format!(
+ "Unevaluated({}, {:?}, {:?})",
+ self.tcx.def_path_str(uv.def.did),
+ uv.substs,
+ uv.promoted,
+ ),
+ ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
+ ty::ConstKind::Error(_) => "Error".to_string(),
+ // These variants shouldn't exist in the MIR.
+ ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Infer(_)
+ | ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal),
+ },
+ // To keep the diffs small, we render this like we render `ty::Const::Value`.
+ //
+ // This changes once `ty::Const::Value` is represented using valtrees.
+ ConstantKind::Val(val, _) => format!("Value({})", fmt_val(&val)),
+ };
+
+ // This reflects what `Const` looked liked before `val` was renamed
+ // as `kind`. We print it like this to avoid having to update
+ // expected output in a lot of tests.
+ self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
+ }
+ }
+
+ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+ self.super_rvalue(rvalue, location);
+ if let Rvalue::Aggregate(kind, _) = rvalue {
+ match **kind {
+ AggregateKind::Closure(def_id, substs) => {
+ self.push("closure");
+ self.push(&format!("+ def_id: {:?}", def_id));
+ self.push(&format!("+ substs: {:#?}", substs));
+ }
+
+ AggregateKind::Generator(def_id, substs, movability) => {
+ self.push("generator");
+ self.push(&format!("+ def_id: {:?}", def_id));
+ self.push(&format!("+ substs: {:#?}", substs));
+ self.push(&format!("+ movability: {:?}", movability));
+ }
+
+ AggregateKind::Adt(_, _, _, Some(user_ty), _) => {
+ self.push("adt");
+ self.push(&format!("+ user_ty: {:?}", user_ty));
+ }
+
+ _ => {}
+ }
+ }
+ }
+}
+
+fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo, function_span: Span) -> String {
+ let location = if tcx.sess.opts.unstable_opts.mir_pretty_relative_line_numbers {
+ tcx.sess.source_map().span_to_relative_line_string(span, function_span)
+ } else {
+ tcx.sess.source_map().span_to_embeddable_string(span)
+ };
+
+ format!("scope {} at {}", scope.index(), location,)
+}
+
+/// Prints local variables in a scope tree.
+fn write_scope_tree(
+ tcx: TyCtxt<'_>,
+ body: &Body<'_>,
+ scope_tree: &FxHashMap<SourceScope, Vec<SourceScope>>,
+ w: &mut dyn Write,
+ parent: SourceScope,
+ depth: usize,
+) -> io::Result<()> {
+ let indent = depth * INDENT.len();
+
+ // Local variable debuginfo.
+ for var_debug_info in &body.var_debug_info {
+ if var_debug_info.source_info.scope != parent {
+ // Not declared in this scope.
+ continue;
+ }
+
+ let indented_debug_info = format!(
+ "{0:1$}debug {2} => {3:?};",
+ INDENT, indent, var_debug_info.name, var_debug_info.value,
+ );
+
+ writeln!(
+ w,
+ "{0:1$} // in {2}",
+ indented_debug_info,
+ ALIGN,
+ comment(tcx, var_debug_info.source_info, body.span),
+ )?;
+ }
+
+ // Local variable types.
+ for (local, local_decl) in body.local_decls.iter_enumerated() {
+ if (1..body.arg_count + 1).contains(&local.index()) {
+ // Skip over argument locals, they're printed in the signature.
+ continue;
+ }
+
+ if local_decl.source_info.scope != parent {
+ // Not declared in this scope.
+ continue;
+ }
+
+ let mut_str = if local_decl.mutability == Mutability::Mut { "mut " } else { "" };
+
+ let mut indented_decl =
+ format!("{0:1$}let {2}{3:?}: {4:?}", INDENT, indent, mut_str, local, local_decl.ty);
+ if let Some(user_ty) = &local_decl.user_ty {
+ for user_ty in user_ty.projections() {
+ write!(indented_decl, " as {:?}", user_ty).unwrap();
+ }
+ }
+ indented_decl.push(';');
+
+ let local_name = if local == RETURN_PLACE { " return place" } else { "" };
+
+ writeln!(
+ w,
+ "{0:1$} //{2} in {3}",
+ indented_decl,
+ ALIGN,
+ local_name,
+ comment(tcx, local_decl.source_info, body.span),
+ )?;
+ }
+
+ let Some(children) = scope_tree.get(&parent) else {
+ return Ok(());
+ };
+
+ for &child in children {
+ let child_data = &body.source_scopes[child];
+ assert_eq!(child_data.parent_scope, Some(parent));
+
+ let (special, span) = if let Some((callee, callsite_span)) = child_data.inlined {
+ (
+ format!(
+ " (inlined {}{})",
+ if callee.def.requires_caller_location(tcx) { "#[track_caller] " } else { "" },
+ callee
+ ),
+ Some(callsite_span),
+ )
+ } else {
+ (String::new(), None)
+ };
+
+ let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special);
+
+ if let Some(span) = span {
+ writeln!(
+ w,
+ "{0:1$} // at {2}",
+ indented_header,
+ ALIGN,
+ tcx.sess.source_map().span_to_embeddable_string(span),
+ )?;
+ } else {
+ writeln!(w, "{}", indented_header)?;
+ }
+
+ write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?;
+ writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
+ }
+
+ Ok(())
+}
+
+/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
+/// local variables (both user-defined bindings and compiler temporaries).
+pub fn write_mir_intro<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'_>,
+ w: &mut dyn Write,
+) -> io::Result<()> {
+ write_mir_sig(tcx, body, w)?;
+ writeln!(w, "{{")?;
+
+ // construct a scope tree and write it out
+ let mut scope_tree: FxHashMap<SourceScope, Vec<SourceScope>> = Default::default();
+ for (index, scope_data) in body.source_scopes.iter().enumerate() {
+ if let Some(parent) = scope_data.parent_scope {
+ scope_tree.entry(parent).or_default().push(SourceScope::new(index));
+ } else {
+ // Only the argument scope has no parent, because it's the root.
+ assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index());
+ }
+ }
+
+ write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?;
+
+ // Add an empty line before the first block is printed.
+ writeln!(w)?;
+
+ Ok(())
+}
+
+/// Find all `AllocId`s mentioned (recursively) in the MIR body and print their corresponding
+/// allocations.
+pub fn write_allocations<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'_>,
+ w: &mut dyn Write,
+) -> io::Result<()> {
+ fn alloc_ids_from_alloc(
+ alloc: ConstAllocation<'_>,
+ ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
+ alloc.inner().relocations().values().map(|id| *id)
+ }
+
+ fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
+ match val {
+ ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
+ Either::Left(Either::Left(std::iter::once(ptr.provenance)))
+ }
+ ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
+ Either::Left(Either::Right(std::iter::empty()))
+ }
+ ConstValue::ZeroSized => Either::Left(Either::Right(std::iter::empty())),
+ ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => {
+ Either::Right(alloc_ids_from_alloc(alloc))
+ }
+ }
+ }
+ struct CollectAllocIds(BTreeSet<AllocId>);
+
+ impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+ fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+ match c.literal {
+ ConstantKind::Ty(c) => self.visit_const(c, loc),
+ ConstantKind::Val(val, _) => {
+ self.0.extend(alloc_ids_from_const_val(val));
+ }
+ }
+ }
+ }
+
+ let mut visitor = CollectAllocIds(Default::default());
+ visitor.visit_body(body);
+
+ // `seen` contains all seen allocations, including the ones we have *not* printed yet.
+ // The protocol is to first `insert` into `seen`, and only if that returns `true`
+ // then push to `todo`.
+ let mut seen = visitor.0;
+ let mut todo: Vec<_> = seen.iter().copied().collect();
+ while let Some(id) = todo.pop() {
+ let mut write_allocation_track_relocs =
+ |w: &mut dyn Write, alloc: ConstAllocation<'tcx>| -> io::Result<()> {
+ // `.rev()` because we are popping them from the back of the `todo` vector.
+ for id in alloc_ids_from_alloc(alloc).rev() {
+ if seen.insert(id) {
+ todo.push(id);
+ }
+ }
+ write!(w, "{}", display_allocation(tcx, alloc.inner()))
+ };
+ write!(w, "\n{id:?}")?;
+ match tcx.try_get_global_alloc(id) {
+ // This can't really happen unless there are bugs, but it doesn't cost us anything to
+ // gracefully handle it and allow buggy rustc to be debugged via allocation printing.
+ None => write!(w, " (deallocated)")?,
+ Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?,
+ Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
+ write!(w, " (vtable: impl {trait_ref} for {ty})")?
+ }
+ Some(GlobalAlloc::VTable(ty, None)) => {
+ write!(w, " (vtable: impl <auto trait> for {ty})")?
+ }
+ Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
+ match tcx.eval_static_initializer(did) {
+ Ok(alloc) => {
+ write!(w, " (static: {}, ", tcx.def_path_str(did))?;
+ write_allocation_track_relocs(w, alloc)?;
+ }
+ Err(_) => write!(
+ w,
+ " (static: {}, error during initializer evaluation)",
+ tcx.def_path_str(did)
+ )?,
+ }
+ }
+ Some(GlobalAlloc::Static(did)) => {
+ write!(w, " (extern static: {})", tcx.def_path_str(did))?
+ }
+ Some(GlobalAlloc::Memory(alloc)) => {
+ write!(w, " (")?;
+ write_allocation_track_relocs(w, alloc)?
+ }
+ }
+ writeln!(w)?;
+ }
+ Ok(())
+}
+
+/// Dumps the size and metadata and content of an allocation to the given writer.
+/// The expectation is that the caller first prints other relevant metadata, so the exact
+/// format of this function is (*without* leading or trailing newline):
+///
+/// ```text
+/// size: {}, align: {}) {
+/// <bytes>
+/// }
+/// ```
+///
+/// The byte format is similar to how hex editors print bytes. Each line starts with the address of
+/// the start of the line, followed by all bytes in hex format (space separated).
+/// If the allocation is small enough to fit into a single line, no start address is given.
+/// After the hex dump, an ascii dump follows, replacing all unprintable characters (control
+/// characters or characters whose value is larger than 127) with a `.`
+/// This also prints relocations adequately.
+pub fn display_allocation<'a, 'tcx, Prov, Extra>(
+ tcx: TyCtxt<'tcx>,
+ alloc: &'a Allocation<Prov, Extra>,
+) -> RenderAllocation<'a, 'tcx, Prov, Extra> {
+ RenderAllocation { tcx, alloc }
+}
+
+#[doc(hidden)]
+pub struct RenderAllocation<'a, 'tcx, Prov, Extra> {
+ tcx: TyCtxt<'tcx>,
+ alloc: &'a Allocation<Prov, Extra>,
+}
+
+impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display
+ for RenderAllocation<'a, 'tcx, Prov, Extra>
+{
+ fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let RenderAllocation { tcx, alloc } = *self;
+ write!(w, "size: {}, align: {})", alloc.size().bytes(), alloc.align.bytes())?;
+ if alloc.size() == Size::ZERO {
+ // We are done.
+ return write!(w, " {{}}");
+ }
+ // Write allocation bytes.
+ writeln!(w, " {{")?;
+ write_allocation_bytes(tcx, alloc, w, " ")?;
+ write!(w, "}}")?;
+ Ok(())
+ }
+}
+
+fn write_allocation_endline(w: &mut dyn std::fmt::Write, ascii: &str) -> std::fmt::Result {
+ for _ in 0..(BYTES_PER_LINE - ascii.chars().count()) {
+ write!(w, " ")?;
+ }
+ writeln!(w, " │ {}", ascii)
+}
+
+/// Number of bytes to print per allocation hex dump line.
+const BYTES_PER_LINE: usize = 16;
+
+/// Prints the line start address and returns the new line start address.
+fn write_allocation_newline(
+ w: &mut dyn std::fmt::Write,
+ mut line_start: Size,
+ ascii: &str,
+ pos_width: usize,
+ prefix: &str,
+) -> Result<Size, std::fmt::Error> {
+ write_allocation_endline(w, ascii)?;
+ line_start += Size::from_bytes(BYTES_PER_LINE);
+ write!(w, "{}0x{:02$x} │ ", prefix, line_start.bytes(), pos_width)?;
+ Ok(line_start)
+}
+
+/// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there
+/// is only one line). Note that your prefix should contain a trailing space as the lines are
+/// printed directly after it.
+fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>(
+ tcx: TyCtxt<'tcx>,
+ alloc: &Allocation<Prov, Extra>,
+ w: &mut dyn std::fmt::Write,
+ prefix: &str,
+) -> std::fmt::Result {
+ let num_lines = alloc.size().bytes_usize().saturating_sub(BYTES_PER_LINE);
+ // Number of chars needed to represent all line numbers.
+ let pos_width = hex_number_length(alloc.size().bytes());
+
+ if num_lines > 0 {
+ write!(w, "{}0x{:02$x} │ ", prefix, 0, pos_width)?;
+ } else {
+ write!(w, "{}", prefix)?;
+ }
+
+ let mut i = Size::ZERO;
+ let mut line_start = Size::ZERO;
+
+ let ptr_size = tcx.data_layout.pointer_size;
+
+ let mut ascii = String::new();
+
+ let oversized_ptr = |target: &mut String, width| {
+ if target.len() > width {
+ write!(target, " ({} ptr bytes)", ptr_size.bytes()).unwrap();
+ }
+ };
+
+ while i < alloc.size() {
+ // The line start already has a space. While we could remove that space from the line start
+ // printing and unconditionally print a space here, that would cause the single-line case
+ // to have a single space before it, which looks weird.
+ if i != line_start {
+ write!(w, " ")?;
+ }
+ if let Some(&prov) = alloc.relocations().get(&i) {
+ // Memory with a relocation must be defined
+ assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
+ let j = i.bytes_usize();
+ let offset = alloc
+ .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
+ let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap();
+ let offset = Size::from_bytes(offset);
+ let relocation_width = |bytes| bytes * 3;
+ let ptr = Pointer::new(prov, offset);
+ let mut target = format!("{:?}", ptr);
+ if target.len() > relocation_width(ptr_size.bytes_usize() - 1) {
+ // This is too long, try to save some space.
+ target = format!("{:#?}", ptr);
+ }
+ if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE {
+ // This branch handles the situation where a relocation starts in the current line
+ // but ends in the next one.
+ let remainder = Size::from_bytes(BYTES_PER_LINE) - (i - line_start);
+ let overflow = ptr_size - remainder;
+ let remainder_width = relocation_width(remainder.bytes_usize()) - 2;
+ let overflow_width = relocation_width(overflow.bytes_usize() - 1) + 1;
+ ascii.push('╾');
+ for _ in 0..remainder.bytes() - 1 {
+ ascii.push('─');
+ }
+ if overflow_width > remainder_width && overflow_width >= target.len() {
+ // The case where the relocation fits into the part in the next line
+ write!(w, "╾{0:─^1$}", "", remainder_width)?;
+ line_start =
+ write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?;
+ ascii.clear();
+ write!(w, "{0:─^1$}╼", target, overflow_width)?;
+ } else {
+ oversized_ptr(&mut target, remainder_width);
+ write!(w, "╾{0:─^1$}", target, remainder_width)?;
+ line_start =
+ write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?;
+ write!(w, "{0:─^1$}╼", "", overflow_width)?;
+ ascii.clear();
+ }
+ for _ in 0..overflow.bytes() - 1 {
+ ascii.push('─');
+ }
+ ascii.push('╼');
+ i += ptr_size;
+ continue;
+ } else {
+ // This branch handles a relocation that starts and ends in the current line.
+ let relocation_width = relocation_width(ptr_size.bytes_usize() - 1);
+ oversized_ptr(&mut target, relocation_width);
+ ascii.push('╾');
+ write!(w, "╾{0:─^1$}╼", target, relocation_width)?;
+ for _ in 0..ptr_size.bytes() - 2 {
+ ascii.push('─');
+ }
+ ascii.push('╼');
+ i += ptr_size;
+ }
+ } else if alloc.init_mask().is_range_initialized(i, i + Size::from_bytes(1)).is_ok() {
+ let j = i.bytes_usize();
+
+ // Checked definedness (and thus range) and relocations. This access also doesn't
+ // influence interpreter execution but is only for debugging.
+ let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
+ write!(w, "{:02x}", c)?;
+ if c.is_ascii_control() || c >= 0x80 {
+ ascii.push('.');
+ } else {
+ ascii.push(char::from(c));
+ }
+ i += Size::from_bytes(1);
+ } else {
+ write!(w, "__")?;
+ ascii.push('░');
+ i += Size::from_bytes(1);
+ }
+ // Print a new line header if the next line still has some bytes to print.
+ if i == line_start + Size::from_bytes(BYTES_PER_LINE) && i != alloc.size() {
+ line_start = write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?;
+ ascii.clear();
+ }
+ }
+ write_allocation_endline(w, &ascii)?;
+
+ Ok(())
+}
+
+fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> {
+ use rustc_hir::def::DefKind;
+
+ trace!("write_mir_sig: {:?}", body.source.instance);
+ let def_id = body.source.def_id();
+ let kind = tcx.def_kind(def_id);
+ let is_function = match kind {
+ DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
+ _ => tcx.is_closure(def_id),
+ };
+ match (kind, body.source.promoted) {
+ (_, Some(i)) => write!(w, "{:?} in ", i)?,
+ (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
+ (DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
+ (DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
+ (_, _) if is_function => write!(w, "fn ")?,
+ (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
+ _ => bug!("Unexpected def kind {:?}", kind),
+ }
+
+ ty::print::with_forced_impl_filename_line! {
+ // see notes on #41697 elsewhere
+ write!(w, "{}", tcx.def_path_str(def_id))?
+ }
+
+ if body.source.promoted.is_none() && is_function {
+ write!(w, "(")?;
+
+ // fn argument types.
+ for (i, arg) in body.args_iter().enumerate() {
+ if i != 0 {
+ write!(w, ", ")?;
+ }
+ write!(w, "{:?}: {}", Place::from(arg), body.local_decls[arg].ty)?;
+ }
+
+ write!(w, ") -> {}", body.return_ty())?;
+ } else {
+ assert_eq!(body.arg_count, 0);
+ write!(w, ": {} =", body.return_ty())?;
+ }
+
+ if let Some(yield_ty) = body.yield_ty() {
+ writeln!(w)?;
+ writeln!(w, "yields {}", yield_ty)?;
+ }
+
+ write!(w, " ")?;
+ // Next thing that gets printed is the opening {
+
+ Ok(())
+}
+
+fn write_user_type_annotations(
+ tcx: TyCtxt<'_>,
+ body: &Body<'_>,
+ w: &mut dyn Write,
+) -> io::Result<()> {
+ if !body.user_type_annotations.is_empty() {
+ writeln!(w, "| User Type Annotations")?;
+ }
+ for (index, annotation) in body.user_type_annotations.iter_enumerated() {
+ writeln!(
+ w,
+ "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
+ index.index(),
+ annotation.user_ty,
+ tcx.sess.source_map().span_to_embeddable_string(annotation.span),
+ annotation.inferred_ty,
+ )?;
+ }
+ if !body.user_type_annotations.is_empty() {
+ writeln!(w, "|")?;
+ }
+ Ok(())
+}
+
+pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option<DefId>) -> Vec<DefId> {
+ if let Some(i) = single {
+ vec![i]
+ } else {
+ tcx.mir_keys(()).iter().map(|def_id| def_id.to_def_id()).collect()
+ }
+}
+
+/// Calc converted u64 decimal into hex and return it's length in chars
+///
+/// ```ignore (cannot-test-private-function)
+/// assert_eq!(1, hex_number_length(0));
+/// assert_eq!(1, hex_number_length(1));
+/// assert_eq!(2, hex_number_length(16));
+/// ```
+fn hex_number_length(x: u64) -> usize {
+ if x == 0 {
+ return 1;
+ }
+ let mut length = 0;
+ let mut x_left = x;
+ while x_left > 0 {
+ x_left /= 16;
+ length += 1;
+ }
+ length
+}
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
new file mode 100644
index 000000000..dd9f8795f
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -0,0 +1,476 @@
+//! Values computed by queries that use MIR.
+
+use crate::mir::{Body, ConstantKind, Promoted};
+use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::vec_map::VecMap;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_index::bit_set::BitMatrix;
+use rustc_index::vec::IndexVec;
+use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
+use smallvec::SmallVec;
+use std::cell::Cell;
+use std::fmt::{self, Debug};
+
+use super::{Field, SourceInfo};
+
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+pub enum UnsafetyViolationKind {
+ /// Unsafe operation outside `unsafe`.
+ General,
+ /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
+ /// Has to be handled as a lint for backwards compatibility.
+ UnsafeFn,
+}
+
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+pub enum UnsafetyViolationDetails {
+ CallToUnsafeFunction,
+ UseOfInlineAssembly,
+ InitializingTypeWith,
+ CastOfPointerToInt,
+ UseOfMutableStatic,
+ UseOfExternStatic,
+ DerefOfRawPointer,
+ AccessToUnionField,
+ MutationOfLayoutConstrainedField,
+ BorrowOfLayoutConstrainedField,
+ CallToFunctionWith,
+}
+
+impl UnsafetyViolationDetails {
+ pub fn description_and_note(&self) -> (&'static str, &'static str) {
+ use UnsafetyViolationDetails::*;
+ match self {
+ CallToUnsafeFunction => (
+ "call to unsafe function",
+ "consult the function's documentation for information on how to avoid undefined \
+ behavior",
+ ),
+ UseOfInlineAssembly => (
+ "use of inline assembly",
+ "inline assembly is entirely unchecked and can cause undefined behavior",
+ ),
+ InitializingTypeWith => (
+ "initializing type with `rustc_layout_scalar_valid_range` attr",
+ "initializing a layout restricted type's field with a value outside the valid \
+ range is undefined behavior",
+ ),
+ CastOfPointerToInt => {
+ ("cast of pointer to int", "casting pointers to integers in constants")
+ }
+ UseOfMutableStatic => (
+ "use of mutable static",
+ "mutable statics can be mutated by multiple threads: aliasing violations or data \
+ races will cause undefined behavior",
+ ),
+ UseOfExternStatic => (
+ "use of extern static",
+ "extern statics are not controlled by the Rust type system: invalid data, \
+ aliasing violations or data races will cause undefined behavior",
+ ),
+ DerefOfRawPointer => (
+ "dereference of raw pointer",
+ "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
+ and cause data races: all of these are undefined behavior",
+ ),
+ AccessToUnionField => (
+ "access to union field",
+ "the field may not be properly initialized: using uninitialized data will cause \
+ undefined behavior",
+ ),
+ MutationOfLayoutConstrainedField => (
+ "mutation of layout constrained field",
+ "mutating layout constrained fields cannot statically be checked for valid values",
+ ),
+ BorrowOfLayoutConstrainedField => (
+ "borrow of layout constrained field with interior mutability",
+ "references to fields of layout constrained fields lose the constraints. Coupled \
+ with interior mutability, the field can be changed to invalid values",
+ ),
+ CallToFunctionWith => (
+ "call to function with `#[target_feature]`",
+ "can only be called if the required target features are available",
+ ),
+ }
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+pub struct UnsafetyViolation {
+ pub source_info: SourceInfo,
+ pub lint_root: hir::HirId,
+ pub kind: UnsafetyViolationKind,
+ pub details: UnsafetyViolationDetails,
+}
+
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+pub enum UnusedUnsafe {
+ /// `unsafe` block contains no unsafe operations
+ /// > ``unnecessary `unsafe` block``
+ Unused,
+ /// `unsafe` block nested under another (used) `unsafe` block
+ /// > ``… because it's nested under this `unsafe` block``
+ InUnsafeBlock(hir::HirId),
+ /// `unsafe` block nested under `unsafe fn`
+ /// > ``… because it's nested under this `unsafe fn` ``
+ ///
+ /// the second HirId here indicates the first usage of the `unsafe` block,
+ /// which allows retrieval of the LintLevelSource for why that operation would
+ /// have been permitted without the block
+ InUnsafeFn(hir::HirId, hir::HirId),
+}
+
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+pub enum UsedUnsafeBlockData {
+ SomeDisallowedInUnsafeFn,
+ // the HirId here indicates the first usage of the `unsafe` block
+ // (i.e. the one that's first encountered in the MIR traversal of the unsafety check)
+ AllAllowedInUnsafeFn(hir::HirId),
+}
+
+#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
+pub struct UnsafetyCheckResult {
+ /// Violations that are propagated *upwards* from this function.
+ pub violations: Vec<UnsafetyViolation>,
+
+ /// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
+ ///
+ /// The keys are the used `unsafe` blocks, the UnusedUnsafeKind indicates whether
+ /// or not any of the usages happen at a place that doesn't allow `unsafe_op_in_unsafe_fn`.
+ pub used_unsafe_blocks: FxHashMap<hir::HirId, UsedUnsafeBlockData>,
+
+ /// This is `Some` iff the item is not a closure.
+ pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
+}
+
+rustc_index::newtype_index! {
+ pub struct GeneratorSavedLocal {
+ derive [HashStable]
+ DEBUG_FORMAT = "_{}",
+ }
+}
+
+/// The layout of generator state.
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+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>>,
+
+ /// The source that led to each variant being created (usually, a yield or
+ /// await).
+ pub variant_source_info: IndexVec<VariantIdx, SourceInfo>,
+
+ /// 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>,
+}
+
+impl Debug for GeneratorLayout<'_> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// Prints an iterator of (key, value) tuples as a map.
+ struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
+ impl<'a, K, V> MapPrinter<'a, K, V> {
+ fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
+ Self(Cell::new(Some(Box::new(iter))))
+ }
+ }
+ impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().entries(self.0.take().unwrap()).finish()
+ }
+ }
+
+ /// Prints the generator variant name.
+ struct GenVariantPrinter(VariantIdx);
+ impl From<VariantIdx> for GenVariantPrinter {
+ fn from(idx: VariantIdx) -> Self {
+ GenVariantPrinter(idx)
+ }
+ }
+ impl Debug for GenVariantPrinter {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let variant_name = ty::GeneratorSubsts::variant_name(self.0);
+ if fmt.alternate() {
+ write!(fmt, "{:9}({:?})", variant_name, self.0)
+ } else {
+ write!(fmt, "{}", variant_name)
+ }
+ }
+ }
+
+ /// Forces its contents to print in regular mode instead of alternate mode.
+ struct OneLinePrinter<T>(T);
+ impl<T: Debug> Debug for OneLinePrinter<T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "{:?}", self.0)
+ }
+ }
+
+ fmt.debug_struct("GeneratorLayout")
+ .field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
+ .field(
+ "variant_fields",
+ &MapPrinter::new(
+ self.variant_fields
+ .iter_enumerated()
+ .map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
+ ),
+ )
+ .field("storage_conflicts", &self.storage_conflicts)
+ .finish()
+ }
+}
+
+#[derive(Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct BorrowCheckResult<'tcx> {
+ /// All the opaque types that are restricted to concrete types
+ /// by this function. Unlike the value in `TypeckResults`, this has
+ /// unerased regions.
+ pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
+ pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
+ pub used_mut_upvars: SmallVec<[Field; 8]>,
+ pub tainted_by_errors: Option<ErrorGuaranteed>,
+}
+
+/// The result of the `mir_const_qualif` query.
+///
+/// Each field (except `error_occurred`) corresponds to an implementer of the `Qualif` trait in
+/// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each
+/// `Qualif`.
+#[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
+pub struct ConstQualifs {
+ pub has_mut_interior: bool,
+ pub needs_drop: bool,
+ pub needs_non_const_drop: bool,
+ pub custom_eq: bool,
+ pub tainted_by_errors: Option<ErrorGuaranteed>,
+}
+
+/// 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 the free regions in the
+/// closure's signature and captures are erased.
+///
+/// Example: If type check produces a closure with the closure substs:
+///
+/// ```text
+/// ClosureSubsts = [
+/// 'a, // From the parent.
+/// 'b,
+/// i8, // the "closure kind"
+/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
+/// &'<erased> String, // some upvar
+/// ]
+/// ```
+///
+/// We would "renumber" each free region to a unique vid, as follows:
+///
+/// ```text
+/// ClosureSubsts = [
+/// '1, // From the parent.
+/// '2,
+/// i8, // the "closure kind"
+/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
+/// &'4 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 using their external names (`ReStatic`,
+/// `ReEarlyBound`, `ReFree`). We use these because in a query response we
+/// cannot use `ReVar` (which is what we use internally within the rest of the
+/// NLL code).
+#[derive(Clone, Debug, TyEncodable, TyDecodable, 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, TyEncodable, TyDecodable, 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<'tcx>,
+}
+
+// Make sure this enum doesn't unintentionally grow
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
+
+/// 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_const_eval::borrow_check::constraints`.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub enum ConstraintCategory<'tcx> {
+ Return(ReturnConstraint),
+ 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,
+
+ /// Contains the function type if available.
+ CallArgument(Option<Ty<'tcx>>),
+ CopyBound,
+ SizedBound,
+ Assignment,
+ /// A constraint that came from a usage of a variable (e.g. in an ADT expression
+ /// like `Foo { field: my_val }`)
+ Usage,
+ OpaqueType,
+ ClosureUpvar(Field),
+
+ /// A constraint from a user-written predicate
+ /// with the provided span, written on the item
+ /// with the given `DefId`
+ Predicate(Span),
+
+ /// 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.
+ Boring,
+ // Boring and applicable everywhere.
+ BoringNoLocation,
+
+ /// A constraint that doesn't correspond to anything the user sees.
+ Internal,
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub enum ReturnConstraint {
+ Normal,
+ ClosureUpvar(Field),
+}
+
+/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
+/// that must outlive some region.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, 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 a type level constant of kind ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredConst<'tcx> {
+ pub variant: Option<VariantIdx>,
+ pub fields: &'tcx [ty::Const<'tcx>],
+}
+
+/// The constituent parts of a mir constant of kind ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredMirConstant<'tcx> {
+ pub variant: Option<VariantIdx>,
+ pub fields: &'tcx [ConstantKind<'tcx>],
+}
+
+/// Coverage information summarized from a MIR if instrumented for source code coverage (see
+/// compiler option `-Cinstrument-coverage`). This information is generated by the
+/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct CoverageInfo {
+ /// The total number of coverage region counters added to the MIR `Body`.
+ pub num_counters: u32,
+
+ /// The total number of coverage region counter expressions added to the MIR `Body`.
+ pub num_expressions: u32,
+}
+
+/// Shims which make dealing with `WithOptConstParam` easier.
+///
+/// For more information on why this is needed, consider looking
+/// at the docs for `WithOptConstParam` itself.
+impl<'tcx> TyCtxt<'tcx> {
+ #[inline]
+ pub fn mir_const_qualif_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<LocalDefId>,
+ ) -> ConstQualifs {
+ if let Some(param_did) = def.const_param_did {
+ self.mir_const_qualif_const_arg((def.did, param_did))
+ } else {
+ self.mir_const_qualif(def.did)
+ }
+ }
+
+ #[inline]
+ pub fn promoted_mir_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<DefId>,
+ ) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
+ if let Some((did, param_did)) = def.as_const_arg() {
+ self.promoted_mir_of_const_arg((did, param_did))
+ } else {
+ self.promoted_mir(def.did)
+ }
+ }
+
+ #[inline]
+ pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
+ if let Some((did, param_did)) = def.as_const_arg() {
+ self.mir_for_ctfe_of_const_arg((did, param_did))
+ } else {
+ self.mir_for_ctfe(def.did)
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
new file mode 100644
index 000000000..4418b848e
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -0,0 +1,691 @@
+use rustc_hir::def_id::DefId;
+use rustc_middle::hir;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::config::MirSpanview;
+use rustc_span::{BytePos, Pos, Span, SyntaxContext};
+
+use std::cmp;
+use std::io::{self, Write};
+
+pub const TOOLTIP_INDENT: &str = " ";
+
+const CARET: char = '\u{2038}'; // Unicode `CARET`
+const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET
+const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET`
+const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">";
+const HEADER: &str = r#"<!DOCTYPE html>
+<html>
+<head>"#;
+const START_BODY: &str = r#"</head>
+<body>"#;
+const FOOTER: &str = r#"</body>
+</html>"#;
+
+const STYLE_SECTION: &str = r#"<style>
+ .line {
+ counter-increment: line;
+ }
+ .line:before {
+ content: counter(line) ": ";
+ font-family: Menlo, Monaco, monospace;
+ font-style: italic;
+ width: 3.8em;
+ display: inline-block;
+ text-align: right;
+ filter: opacity(50%);
+ -webkit-user-select: none;
+ }
+ .code {
+ color: #dddddd;
+ background-color: #222222;
+ font-family: Menlo, Monaco, monospace;
+ line-height: 1.4em;
+ border-bottom: 2px solid #222222;
+ white-space: pre;
+ display: inline-block;
+ }
+ .odd {
+ background-color: #55bbff;
+ color: #223311;
+ }
+ .even {
+ background-color: #ee7756;
+ color: #551133;
+ }
+ .code {
+ --index: calc(var(--layer) - 1);
+ padding-top: calc(var(--index) * 0.15em);
+ filter:
+ hue-rotate(calc(var(--index) * 25deg))
+ saturate(calc(100% - (var(--index) * 2%)))
+ brightness(calc(100% - (var(--index) * 1.5%)));
+ }
+ .annotation {
+ color: #4444ff;
+ font-family: monospace;
+ font-style: italic;
+ display: none;
+ -webkit-user-select: none;
+ }
+ body:active .annotation {
+ /* requires holding mouse down anywhere on the page */
+ display: inline-block;
+ }
+ span:hover .annotation {
+ /* requires hover over a span ONLY on its first line */
+ display: inline-block;
+ }
+</style>"#;
+
+/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator.
+#[derive(Clone, Debug)]
+pub struct SpanViewable {
+ pub bb: BasicBlock,
+ pub span: Span,
+ pub id: String,
+ pub tooltip: String,
+}
+
+/// Write a spanview HTML+CSS file to analyze MIR element spans.
+pub fn write_mir_fn_spanview<'tcx, W>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
+ spanview: MirSpanview,
+ title: &str,
+ w: &mut W,
+) -> io::Result<()>
+where
+ W: Write,
+{
+ let def_id = body.source.def_id();
+ let hir_body = hir_body(tcx, def_id);
+ if hir_body.is_none() {
+ return Ok(());
+ }
+ let body_span = hir_body.unwrap().value.span;
+ let mut span_viewables = Vec::new();
+ for (bb, data) in body.basic_blocks().iter_enumerated() {
+ match spanview {
+ MirSpanview::Statement => {
+ for (i, statement) in data.statements.iter().enumerate() {
+ if let Some(span_viewable) =
+ statement_span_viewable(tcx, body_span, bb, i, statement)
+ {
+ span_viewables.push(span_viewable);
+ }
+ }
+ if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) {
+ span_viewables.push(span_viewable);
+ }
+ }
+ MirSpanview::Terminator => {
+ if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) {
+ span_viewables.push(span_viewable);
+ }
+ }
+ MirSpanview::Block => {
+ if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) {
+ span_viewables.push(span_viewable);
+ }
+ }
+ }
+ }
+ write_document(tcx, fn_span(tcx, def_id), span_viewables, title, w)?;
+ Ok(())
+}
+
+/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated
+/// list `SpanViewable`s.
+pub fn write_document<'tcx, W>(
+ tcx: TyCtxt<'tcx>,
+ spanview_span: Span,
+ mut span_viewables: Vec<SpanViewable>,
+ title: &str,
+ w: &mut W,
+) -> io::Result<()>
+where
+ W: Write,
+{
+ let mut from_pos = spanview_span.lo();
+ let end_pos = spanview_span.hi();
+ let source_map = tcx.sess.source_map();
+ let start = source_map.lookup_char_pos(from_pos);
+ let indent_to_initial_start_col = " ".repeat(start.col.to_usize());
+ debug!(
+ "spanview_span={:?}; source is:\n{}{}",
+ spanview_span,
+ indent_to_initial_start_col,
+ source_map.span_to_snippet(spanview_span).expect("function should have printable source")
+ );
+ writeln!(w, "{}", HEADER)?;
+ writeln!(w, "<title>{}</title>", title)?;
+ writeln!(w, "{}", STYLE_SECTION)?;
+ writeln!(w, "{}", START_BODY)?;
+ write!(
+ w,
+ r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#,
+ start.line - 1,
+ indent_to_initial_start_col,
+ )?;
+ span_viewables.sort_unstable_by(|a, b| {
+ let a = a.span;
+ let b = b.span;
+ if a.lo() == b.lo() {
+ // Sort hi() in reverse order so shorter spans are attempted after longer spans.
+ // This should give shorter spans a higher "layer", so they are not covered by
+ // the longer spans.
+ b.hi().partial_cmp(&a.hi())
+ } else {
+ a.lo().partial_cmp(&b.lo())
+ }
+ .unwrap()
+ });
+ let mut ordered_viewables = &span_viewables[..];
+ const LOWEST_VIEWABLE_LAYER: usize = 1;
+ let mut alt = false;
+ while ordered_viewables.len() > 0 {
+ debug!(
+ "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}",
+ from_pos.to_usize(),
+ end_pos.to_usize(),
+ ordered_viewables.len()
+ );
+ let curr_id = &ordered_viewables[0].id;
+ let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps(
+ tcx,
+ from_pos,
+ end_pos,
+ ordered_viewables,
+ alt,
+ LOWEST_VIEWABLE_LAYER,
+ w,
+ )?;
+ debug!(
+ "DONE calling write_next_viewable, with new from_pos={}, \
+ and remaining viewables len={}",
+ next_from_pos.to_usize(),
+ next_ordered_viewables.len()
+ );
+ assert!(
+ from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(),
+ "write_next_viewable_with_overlaps() must make a state change"
+ );
+ from_pos = next_from_pos;
+ if next_ordered_viewables.len() != ordered_viewables.len() {
+ ordered_viewables = next_ordered_viewables;
+ if let Some(next_ordered_viewable) = ordered_viewables.first() {
+ if &next_ordered_viewable.id != curr_id {
+ alt = !alt;
+ }
+ }
+ }
+ }
+ if from_pos < end_pos {
+ write_coverage_gap(tcx, from_pos, end_pos, w)?;
+ }
+ writeln!(w, r#"</span></div>"#)?;
+ writeln!(w, "{}", FOOTER)?;
+ Ok(())
+}
+
+/// Format a string showing the start line and column, and end line and column within a file.
+pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
+ let source_map = tcx.sess.source_map();
+ let start = source_map.lookup_char_pos(span.lo());
+ let end = source_map.lookup_char_pos(span.hi());
+ format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1)
+}
+
+pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
+ use StatementKind::*;
+ match statement.kind {
+ Assign(..) => "Assign",
+ FakeRead(..) => "FakeRead",
+ SetDiscriminant { .. } => "SetDiscriminant",
+ Deinit(..) => "Deinit",
+ StorageLive(..) => "StorageLive",
+ StorageDead(..) => "StorageDead",
+ Retag(..) => "Retag",
+ AscribeUserType(..) => "AscribeUserType",
+ Coverage(..) => "Coverage",
+ CopyNonOverlapping(..) => "CopyNonOverlapping",
+ Nop => "Nop",
+ }
+}
+
+pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
+ use TerminatorKind::*;
+ match term.kind {
+ Goto { .. } => "Goto",
+ SwitchInt { .. } => "SwitchInt",
+ Resume => "Resume",
+ Abort => "Abort",
+ Return => "Return",
+ Unreachable => "Unreachable",
+ Drop { .. } => "Drop",
+ DropAndReplace { .. } => "DropAndReplace",
+ Call { .. } => "Call",
+ Assert { .. } => "Assert",
+ Yield { .. } => "Yield",
+ GeneratorDrop => "GeneratorDrop",
+ FalseEdge { .. } => "FalseEdge",
+ FalseUnwind { .. } => "FalseUnwind",
+ InlineAsm { .. } => "InlineAsm",
+ }
+}
+
+fn statement_span_viewable<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body_span: Span,
+ bb: BasicBlock,
+ i: usize,
+ statement: &Statement<'tcx>,
+) -> Option<SpanViewable> {
+ let span = statement.source_info.span;
+ if !body_span.contains(span) {
+ return None;
+ }
+ let id = format!("{}[{}]", bb.index(), i);
+ let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None);
+ Some(SpanViewable { bb, span, id, tooltip })
+}
+
+fn terminator_span_viewable<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body_span: Span,
+ bb: BasicBlock,
+ data: &BasicBlockData<'tcx>,
+) -> Option<SpanViewable> {
+ let term = data.terminator();
+ let span = term.source_info.span;
+ if !body_span.contains(span) {
+ return None;
+ }
+ let id = format!("{}:{}", bb.index(), terminator_kind_name(term));
+ let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator);
+ Some(SpanViewable { bb, span, id, tooltip })
+}
+
+fn block_span_viewable<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body_span: Span,
+ bb: BasicBlock,
+ data: &BasicBlockData<'tcx>,
+) -> Option<SpanViewable> {
+ let span = compute_block_span(data, body_span);
+ if !body_span.contains(span) {
+ return None;
+ }
+ let id = format!("{}", bb.index());
+ let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator);
+ Some(SpanViewable { bb, span, id, tooltip })
+}
+
+fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span {
+ let mut span = data.terminator().source_info.span;
+ for statement_span in data.statements.iter().map(|statement| statement.source_info.span) {
+ // Only combine Spans from the root context, and within the function's body_span.
+ if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) {
+ span = span.to(statement_span);
+ }
+ }
+ span
+}
+
+/// Recursively process each ordered span. Spans that overlap will have progressively varying
+/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will
+/// have alternating style choices, to help distinguish between them if, visually adjacent.
+/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true
+/// and false, for each adjacent non-overlapping span. Source code between the spans (code
+/// that is not in any coverage region) has neutral styling.
+fn write_next_viewable_with_overlaps<'tcx, 'b, W>(
+ tcx: TyCtxt<'tcx>,
+ mut from_pos: BytePos,
+ mut to_pos: BytePos,
+ ordered_viewables: &'b [SpanViewable],
+ alt: bool,
+ layer: usize,
+ w: &mut W,
+) -> io::Result<(BytePos, &'b [SpanViewable])>
+where
+ W: Write,
+{
+ let debug_indent = " ".repeat(layer);
+ let (viewable, mut remaining_viewables) =
+ ordered_viewables.split_first().expect("ordered_viewables should have some");
+
+ if from_pos < viewable.span.lo() {
+ debug!(
+ "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \
+ of {:?}), with to_pos={}",
+ debug_indent,
+ from_pos.to_usize(),
+ viewable.span.lo().to_usize(),
+ viewable.span,
+ to_pos.to_usize()
+ );
+ let hi = cmp::min(viewable.span.lo(), to_pos);
+ write_coverage_gap(tcx, from_pos, hi, w)?;
+ from_pos = hi;
+ if from_pos < viewable.span.lo() {
+ debug!(
+ "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}",
+ debug_indent,
+ from_pos.to_usize()
+ );
+ return Ok((from_pos, ordered_viewables));
+ }
+ }
+
+ if from_pos < viewable.span.hi() {
+ // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing
+ // with room to print the tail.
+ to_pos = cmp::min(viewable.span.hi(), to_pos);
+ debug!(
+ "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}",
+ debug_indent,
+ viewable.span.hi().to_usize(),
+ to_pos.to_usize()
+ );
+ }
+
+ let mut subalt = false;
+ while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) {
+ let overlapping_viewable = &remaining_viewables[0];
+ debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span);
+
+ let span =
+ trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos));
+ let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() {
+ // `viewable` is not yet fully rendered, so start writing the span, up to either the
+ // `to_pos` or the next `overlapping_viewable`, whichever comes first.
+ debug!(
+ "{}make html_snippet (may not write it if early exit) for partial span {:?} \
+ of viewable.span {:?}",
+ debug_indent, span, viewable.span
+ );
+ from_pos = span.hi();
+ make_html_snippet(tcx, span, Some(&viewable))
+ } else {
+ None
+ };
+
+ // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans.
+ // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early
+ // exit, there should be another opportunity to write the tail marker.
+ if !span.is_empty() {
+ if let Some(ref html_snippet) = some_html_snippet {
+ debug!(
+ "{}write html_snippet for that partial span of viewable.span {:?}",
+ debug_indent, viewable.span
+ );
+ write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
+ }
+ some_html_snippet = None;
+ }
+
+ if from_pos < overlapping_viewable.span.lo() {
+ debug!(
+ "{}EARLY RETURN: from_pos={} has not yet reached the \
+ overlapping_viewable.span {:?}",
+ debug_indent,
+ from_pos.to_usize(),
+ overlapping_viewable.span
+ );
+ // must have reached `to_pos` before reaching the start of the
+ // `overlapping_viewable.span`
+ return Ok((from_pos, ordered_viewables));
+ }
+
+ if from_pos == to_pos
+ && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty())
+ {
+ debug!(
+ "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \
+ empty, or not from_pos",
+ debug_indent,
+ to_pos.to_usize(),
+ overlapping_viewable.span
+ );
+ // `to_pos` must have occurred before the overlapping viewable. Return
+ // `ordered_viewables` so we can continue rendering the `viewable`, from after the
+ // `to_pos`.
+ return Ok((from_pos, ordered_viewables));
+ }
+
+ if let Some(ref html_snippet) = some_html_snippet {
+ debug!(
+ "{}write html_snippet for that partial span of viewable.span {:?}",
+ debug_indent, viewable.span
+ );
+ write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
+ }
+
+ debug!(
+ "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \
+ and viewables len={}",
+ debug_indent,
+ from_pos.to_usize(),
+ to_pos.to_usize(),
+ remaining_viewables.len()
+ );
+ // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`.
+ let curr_id = &remaining_viewables[0].id;
+ let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps(
+ tcx,
+ from_pos,
+ to_pos,
+ &remaining_viewables,
+ subalt,
+ layer + 1,
+ w,
+ )?;
+ debug!(
+ "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \
+ viewables len={}",
+ debug_indent,
+ next_from_pos.to_usize(),
+ next_remaining_viewables.len()
+ );
+ assert!(
+ from_pos != next_from_pos
+ || remaining_viewables.len() != next_remaining_viewables.len(),
+ "write_next_viewable_with_overlaps() must make a state change"
+ );
+ from_pos = next_from_pos;
+ if next_remaining_viewables.len() != remaining_viewables.len() {
+ remaining_viewables = next_remaining_viewables;
+ if let Some(next_ordered_viewable) = remaining_viewables.first() {
+ if &next_ordered_viewable.id != curr_id {
+ subalt = !subalt;
+ }
+ }
+ }
+ }
+ if from_pos <= viewable.span.hi() {
+ let span = trim_span(viewable.span, from_pos, to_pos);
+ debug!(
+ "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}",
+ debug_indent, span, viewable.span
+ );
+ if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) {
+ from_pos = span.hi();
+ write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
+ }
+ }
+ debug!("{}RETURN: No more overlap", debug_indent);
+ Ok((
+ from_pos,
+ if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables },
+ ))
+}
+
+#[inline(always)]
+fn write_coverage_gap<'tcx, W>(
+ tcx: TyCtxt<'tcx>,
+ lo: BytePos,
+ hi: BytePos,
+ w: &mut W,
+) -> io::Result<()>
+where
+ W: Write,
+{
+ let span = Span::with_root_ctxt(lo, hi);
+ if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) {
+ write_span(html_snippet, "", false, 0, w)
+ } else {
+ Ok(())
+ }
+}
+
+fn write_span<W>(
+ html_snippet: &str,
+ tooltip: &str,
+ alt: bool,
+ layer: usize,
+ w: &mut W,
+) -> io::Result<()>
+where
+ W: Write,
+{
+ let maybe_alt_class = if layer > 0 {
+ if alt { " odd" } else { " even" }
+ } else {
+ ""
+ };
+ let maybe_title_attr = if !tooltip.is_empty() {
+ format!(" title=\"{}\"", escape_attr(tooltip))
+ } else {
+ "".to_owned()
+ };
+ if layer == 1 {
+ write!(w, "<span>")?;
+ }
+ for (i, line) in html_snippet.lines().enumerate() {
+ if i > 0 {
+ write!(w, "{}", NEW_LINE_SPAN)?;
+ }
+ write!(
+ w,
+ r#"<span class="code{}" style="--layer: {}"{}>{}</span>"#,
+ maybe_alt_class, layer, maybe_title_attr, line
+ )?;
+ }
+ // Check for and translate trailing newlines, because `str::lines()` ignores them
+ if html_snippet.ends_with('\n') {
+ write!(w, "{}", NEW_LINE_SPAN)?;
+ }
+ if layer == 1 {
+ write!(w, "</span>")?;
+ }
+ Ok(())
+}
+
+fn make_html_snippet<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ some_viewable: Option<&SpanViewable>,
+) -> Option<String> {
+ let source_map = tcx.sess.source_map();
+ let snippet = source_map
+ .span_to_snippet(span)
+ .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err));
+ let html_snippet = if let Some(viewable) = some_viewable {
+ let is_head = span.lo() == viewable.span.lo();
+ let is_tail = span.hi() == viewable.span.hi();
+ let mut labeled_snippet = if is_head {
+ format!(r#"<span class="annotation">{}{}</span>"#, viewable.id, ANNOTATION_LEFT_BRACKET)
+ } else {
+ "".to_owned()
+ };
+ if span.is_empty() {
+ if is_head && is_tail {
+ labeled_snippet.push(CARET);
+ }
+ } else {
+ labeled_snippet.push_str(&escape_html(&snippet));
+ };
+ if is_tail {
+ labeled_snippet.push_str(&format!(
+ r#"<span class="annotation">{}{}</span>"#,
+ ANNOTATION_RIGHT_BRACKET, viewable.id
+ ));
+ }
+ labeled_snippet
+ } else {
+ escape_html(&snippet)
+ };
+ if html_snippet.is_empty() { None } else { Some(html_snippet) }
+}
+
+fn tooltip<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ spanview_id: &str,
+ span: Span,
+ statements: Vec<Statement<'tcx>>,
+ terminator: &Option<Terminator<'tcx>>,
+) -> String {
+ let source_map = tcx.sess.source_map();
+ let mut text = Vec::new();
+ text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span)));
+ for statement in statements {
+ let source_range = source_range_no_file(tcx, statement.source_info.span);
+ text.push(format!(
+ "\n{}{}: {}: {:?}",
+ TOOLTIP_INDENT,
+ source_range,
+ statement_kind_name(&statement),
+ statement
+ ));
+ }
+ if let Some(term) = terminator {
+ let source_range = source_range_no_file(tcx, term.source_info.span);
+ text.push(format!(
+ "\n{}{}: {}: {:?}",
+ TOOLTIP_INDENT,
+ source_range,
+ terminator_kind_name(term),
+ term.kind
+ ));
+ }
+ text.join("")
+}
+
+fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span {
+ trim_span_hi(trim_span_lo(span, from_pos), to_pos)
+}
+
+fn trim_span_lo(span: Span, from_pos: BytePos) -> Span {
+ if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) }
+}
+
+fn trim_span_hi(span: Span, to_pos: BytePos) -> Span {
+ if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) }
+}
+
+fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
+ let fn_decl_span = tcx.def_span(def_id);
+ if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
+ if fn_decl_span.eq_ctxt(body_span) { fn_decl_span.to(body_span) } else { body_span }
+ } else {
+ fn_decl_span
+ }
+}
+
+fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> {
+ let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
+ hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id))
+}
+
+fn escape_html(s: &str) -> String {
+ s.replace('&', "&amp;").replace('<', "&lt;").replace('>', "&gt;")
+}
+
+fn escape_attr(s: &str) -> String {
+ s.replace('&', "&amp;")
+ .replace('\"', "&quot;")
+ .replace('\'', "&#39;")
+ .replace('<', "&lt;")
+ .replace('>', "&gt;")
+}
diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs
new file mode 100644
index 000000000..b91c0c257
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/switch_sources.rs
@@ -0,0 +1,78 @@
+//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
+//! `Predecessors`/`PredecessorCache`.
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_index::vec::IndexVec;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use smallvec::SmallVec;
+
+use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
+
+pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
+
+#[derive(Clone, Debug)]
+pub(super) struct SwitchSourceCache {
+ cache: OnceCell<SwitchSources>,
+}
+
+impl SwitchSourceCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ SwitchSourceCache { cache: OnceCell::new() }
+ }
+
+ /// Invalidates the switch source cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ self.cache = OnceCell::new();
+ }
+
+ /// Returns the switch sources for this MIR.
+ #[inline]
+ pub(super) fn compute(
+ &self,
+ basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
+ ) -> &SwitchSources {
+ self.cache.get_or_init(|| {
+ let mut switch_sources: SwitchSources = FxHashMap::default();
+ for (bb, data) in basic_blocks.iter_enumerated() {
+ if let Some(Terminator {
+ kind: TerminatorKind::SwitchInt { targets, .. }, ..
+ }) = &data.terminator
+ {
+ for (value, target) in targets.iter() {
+ switch_sources.entry((target, bb)).or_default().push(Some(value));
+ }
+ switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
+ }
+ }
+
+ switch_sources
+ })
+ }
+}
+
+impl<S: Encoder> Encodable<S> for SwitchSourceCache {
+ #[inline]
+ fn encode(&self, _s: &mut S) {}
+}
+
+impl<D: Decoder> Decodable<D> for SwitchSourceCache {
+ #[inline]
+ fn decode(_: &mut D) -> Self {
+ Self::new()
+ }
+}
+
+impl<CTX> HashStable<CTX> for SwitchSourceCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ SwitchSourceCache,
+}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
new file mode 100644
index 000000000..eb90169d0
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -0,0 +1,1168 @@
+//! This defines the syntax of MIR, i.e., the set of available MIR operations, and other definitions
+//! closely related to MIR semantics.
+//! This is in a dedicated file so that changes to this file can be reviewed more carefully.
+//! The intention is that this file only contains datatype declarations, no code.
+
+use super::{BasicBlock, Constant, Field, Local, SwitchTargets, UserTypeProjection};
+
+use crate::mir::coverage::{CodeRegion, CoverageKind};
+use crate::ty::adjustment::PointerCast;
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, List, Ty};
+use crate::ty::{Region, UserTypeAnnotationIndex};
+
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir};
+use rustc_hir::{self, GeneratorKind};
+use rustc_target::abi::VariantIdx;
+
+use rustc_ast::Mutability;
+use rustc_span::def_id::LocalDefId;
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
+use rustc_target::asm::InlineAsmRegOrRegClass;
+
+/// The various "big phases" that MIR goes through.
+///
+/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
+/// dialects forbid certain variants or values in certain phases. The sections below summarize the
+/// changes, but do not document them thoroughly. The full documentation is found in the appropriate
+/// documentation for the thing the change is affecting.
+///
+/// Warning: ordering of variants is significant.
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable)]
+pub enum MirPhase {
+ /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also
+ /// the MIR that analysis such as borrowck uses.
+ ///
+ /// One important thing to remember about the behavior of this section of MIR is that drop terminators
+ /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each
+ /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop
+ /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize
+ /// when things are initialized and when things are de-initialized. That means any code running on this
+ /// version of MIR must be sure to produce output that drop elaboration can reason about. See the
+ /// section on the drop terminatorss for more details.
+ Built = 0,
+ // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
+ // We used to have this for pre-miri MIR based const eval.
+ Const = 1,
+ /// This phase checks the MIR for promotable elements and takes them out of the main MIR body
+ /// by creating a new MIR body per promoted element. After this phase (and thus the termination
+ /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
+ /// query.
+ ConstsPromoted = 2,
+ /// After this projections may only contain deref projections as the first element.
+ Derefered = 3,
+ /// Beginning with this phase, the following variants are disallowed:
+ /// * [`TerminatorKind::DropAndReplace`]
+ /// * [`TerminatorKind::FalseUnwind`]
+ /// * [`TerminatorKind::FalseEdge`]
+ /// * [`StatementKind::FakeRead`]
+ /// * [`StatementKind::AscribeUserType`]
+ /// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
+ ///
+ /// And the following variant is allowed:
+ /// * [`StatementKind::Retag`]
+ ///
+ /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
+ /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
+ /// are allowed for non-`Copy` types.
+ DropsLowered = 4,
+ /// Beginning with this phase, the following variant is disallowed:
+ /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
+ ///
+ /// And the following variant is allowed:
+ /// * [`StatementKind::SetDiscriminant`]
+ Deaggregated = 5,
+ /// Before this phase, generators are in the "source code" form, featuring `yield` statements
+ /// and such. With this phase change, they are transformed into a proper state machine. Running
+ /// optimizations before this change can be potentially dangerous because the source code is to
+ /// some extent a "lie." In particular, `yield` terminators effectively make the value of all
+ /// locals visible to the caller. This means that dead store elimination before them, or code
+ /// motion across them, is not correct in general. This is also exasperated by type checking
+ /// having pre-computed a list of the types that it thinks are ok to be live across a yield
+ /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new
+ /// types across a yield point will lead to ICEs becaues of this.
+ ///
+ /// Beginning with this phase, the following variants are disallowed:
+ /// * [`TerminatorKind::Yield`]
+ /// * [`TerminatorKind::GeneratorDrop`]
+ /// * [`ProjectionElem::Deref`] of `Box`
+ GeneratorsLowered = 6,
+ Optimized = 7,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Borrow kinds
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(Hash, 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:
+ /// ```compile_fail,E0510
+ /// 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 mut z = 3;
+ /// let x: &mut isize = &mut z;
+ /// 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:
+ /// ```compile_fail,E0594
+ /// struct Env<'a> { x: &'a &'a mut isize }
+ /// let mut z = 3;
+ /// let x: &mut isize = &mut z;
+ /// let y = (&mut Env { x: &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:
+ /// ```compile_fail,E0596
+ /// struct Env<'a> { x: &'a mut &'a mut isize }
+ /// let mut z = 3;
+ /// let x: &mut isize = &mut z;
+ /// let y = (&mut Env { x: &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,
+ },
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Statements
+
+/// The various kinds of statements that can appear in MIR.
+///
+/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
+/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
+/// causing an ICE if they are violated.
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum StatementKind<'tcx> {
+ /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
+ /// without the possibility of dropping the previous value (that must be done separately, if at
+ /// all). The *exact* way this works is undecided. It probably does something like evaluating
+ /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various
+ /// parts of this may do type specific things that are more complicated than simply copying
+ /// bytes.
+ ///
+ /// **Needs clarification**: The implication of the above idea would be that assignment implies
+ /// that the resulting value is initialized. I believe we could commit to this separately from
+ /// committing to whatever part of the memory model we would need to decide on to make the above
+ /// paragragh precise. Do we want to?
+ ///
+ /// Assignments in which the types of the place and rvalue differ are not well-formed.
+ ///
+ /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for
+ /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we
+ /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this
+ /// interesting for optimizations? Do we want to allow such optimizations?
+ ///
+ /// **Needs clarification**: We currently require that the LHS place not overlap with any place
+ /// read as part of computation of the RHS for some rvalues (generally those not producing
+ /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion,
+ /// it is also unclear in what order the components are evaluated.
+ ///
+ /// [#68364]: https://github.com/rust-lang/rust/issues/68364
+ ///
+ /// See [`Rvalue`] documentation for details on each of those.
+ 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: ! = ..;`
+ ///
+ /// When executed at runtime this is a nop.
+ ///
+ /// Disallowed after drop elaboration.
+ FakeRead(Box<(FakeReadCause, Place<'tcx>)>),
+
+ /// Write the discriminant for a variant to the enum Place.
+ ///
+ /// This is permitted for both generators and ADTs. This does not necessarily write to the
+ /// entire place; instead, it writes to the minimum set of bytes as required by the layout for
+ /// the type.
+ SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
+
+ /// Deinitializes the place.
+ ///
+ /// This writes `uninit` bytes to the entire place.
+ Deinit(Box<Place<'tcx>>),
+
+ /// `StorageLive` and `StorageDead` statements mark the live range of a local.
+ ///
+ /// At any point during the execution of a function, each local is either allocated or
+ /// unallocated. Except as noted below, all locals except function parameters are initially
+ /// unallocated. `StorageLive` statements cause memory to be allocated for the local while
+ /// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only
+ /// reading/writing from it) while it is unallocated is UB.
+ ///
+ /// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body.
+ /// These locals are implicitly allocated for the full duration of the function. There is a
+ /// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for
+ /// computing these locals.
+ ///
+ /// If the local is already allocated, calling `StorageLive` again is UB. However, for an
+ /// unallocated local an additional `StorageDead` all is simply a nop.
+ StorageLive(Local),
+
+ /// See `StorageLive` above.
+ StorageDead(Local),
+
+ /// 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.
+ ///
+ /// For code that is not specific to stacked borrows, you should consider retags to read
+ /// and modify the place in an opaque way.
+ 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:
+ /// ```ignore (illustrative)
+ /// 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
+ ///
+ /// When executed at runtime this is a nop.
+ ///
+ /// Disallowed after drop elaboration.
+ AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
+
+ /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
+ /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage
+ /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates
+ /// executable code, to increment a counter variable at runtime, each time the code region is
+ /// executed.
+ Coverage(Box<Coverage>),
+
+ /// Denotes a call to the intrinsic function `copy_nonoverlapping`.
+ ///
+ /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
+ /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and
+ /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of
+ /// the `src` place are copied to the continguous range of bytes beginning with the first byte
+ /// of `dest`.
+ ///
+ /// **Needs clarification**: In what order are operands computed and dereferenced? It should
+ /// probably match the order for assignment, but that is also undecided.
+ ///
+ /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
+ /// I vaguely remember Ralf saying somewhere that he thought it should not be.
+ CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
+
+ /// No-op. Useful for deleting instructions without affecting statement indices.
+ Nop,
+}
+
+/// Describes what kind of retag is to be performed.
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
+#[rustc_pass_by_value]
+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, TyEncodable, TyDecodable, Debug, Hash, 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.
+ ///
+ /// If a closure pattern matches a Place starting with an Upvar, then we introduce a
+ /// FakeRead for that Place outside the closure, in such a case this option would be
+ /// Some(closure_def_id).
+ /// Otherwise, the value of the optional LocalDefId will be None.
+ //
+ // We can use LocaDefId here since fake read statements are removed
+ // before codegen in the `CleanupNonCodegenStatements` pass.
+ ForMatchedPlace(Option<LocalDefId>),
+
+ /// A fake read of the RefWithinGuard version of a bind-by-value variable
+ /// in a match guard to ensure that its 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.
+ ///
+ /// If a closure pattern matches a Place starting with an Upvar, then we introduce a
+ /// FakeRead for that Place outside the closure, in such a case this option would be
+ /// Some(closure_def_id).
+ /// Otherwise, the value of the optional DefId will be None.
+ ForLet(Option<LocalDefId>),
+
+ /// 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, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct Coverage {
+ pub kind: CoverageKind,
+ pub code_region: Option<CodeRegion>,
+}
+
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct CopyNonOverlapping<'tcx> {
+ pub src: Operand<'tcx>,
+ pub dst: Operand<'tcx>,
+ /// Number of elements to copy from src to dest, not bytes.
+ pub count: Operand<'tcx>,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Terminators
+
+/// The various kinds of terminators, representing ways of exiting from a basic block.
+///
+/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
+/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
+/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
+/// once the current function is reached, execution continues at the given basic block, if any. If
+/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
+/// equivalent to the execution of a `Resume` terminator.
+///
+/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
+/// basic blocks have a couple restrictions:
+/// 1. All `cleanup` fields in them must be `None`.
+/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
+/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
+/// must also be `cleanup`. This is a part of the type system and checked statically, so it is
+/// still an error to have such an edge in the CFG even if it's known that it won't be taken at
+/// runtime.
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+pub enum TerminatorKind<'tcx> {
+ /// Block has one successor; we continue execution there.
+ Goto { target: BasicBlock },
+
+ /// Switches based on the computed value.
+ ///
+ /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned
+ /// integer, char, or bool, and must match the given type. Then, if the list of switch targets
+ /// contains the computed value, continues execution at the associated basic block. Otherwise,
+ /// continues execution at the "otherwise" basic block.
+ ///
+ /// Target values may not appear more than once.
+ SwitchInt {
+ /// The discriminant value being tested.
+ discr: Operand<'tcx>,
+
+ /// The type of value being tested.
+ /// This is always the same as the type of `discr`.
+ /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
+ switch_ty: Ty<'tcx>,
+
+ targets: SwitchTargets,
+ },
+
+ /// Indicates that the landing pad is finished and that the process should continue unwinding.
+ ///
+ /// Like a return, this marks the end of this invocation of the function.
+ ///
+ /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
+ /// deaggregation runs.
+ Resume,
+
+ /// Indicates that the landing pad is finished and that the process should abort.
+ ///
+ /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
+ /// cleanup blocks.
+ Abort,
+
+ /// Returns from the function.
+ ///
+ /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very
+ /// likely at least assigns the value currently in the return place (`_0`) to the place
+ /// specified in the associated `Call` terminator in the calling function, as if assigned via
+ /// `dest = move _0`. It might additionally do other things, like have side-effects in the
+ /// aliasing model.
+ ///
+ /// If the body is a generator body, this has slightly different semantics; it instead causes a
+ /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned
+ /// to the return place.
+ Return,
+
+ /// Indicates a terminator that can never be reached.
+ ///
+ /// Executing this terminator is UB.
+ Unreachable,
+
+ /// The behavior of this statement differs significantly before and after drop elaboration.
+ /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
+ /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
+ /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
+ /// issue tracking if drop glue has any interesting semantics in addition to those of a function
+ /// call?)
+ ///
+ /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
+ /// `Drop` will be executed if...
+ ///
+ /// **Needs clarification**: End of that sentence. This in effect should document the exact
+ /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
+ ///
+ /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
+ /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
+ /// > consider indirect assignments.
+ Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
+
+ /// Drops the place and assigns a new value to it.
+ ///
+ /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
+ /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
+ /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
+ /// explained by the elaboration:
+ ///
+ /// ```ignore (MIR)
+ /// BB0 {
+ /// DropAndReplace(P <- V, goto BB1, unwind BB2)
+ /// }
+ /// ```
+ ///
+ /// becomes
+ ///
+ /// ```ignore (MIR)
+ /// BB0 {
+ /// Drop(P, goto BB1, unwind BB2)
+ /// }
+ /// BB1 {
+ /// // P is now uninitialized
+ /// P <- V
+ /// }
+ /// BB2 {
+ /// // P is now uninitialized -- its dtor panicked
+ /// P <- V
+ /// }
+ /// ```
+ ///
+ /// Disallowed after drop elaboration.
+ DropAndReplace {
+ place: Place<'tcx>,
+ value: Operand<'tcx>,
+ target: BasicBlock,
+ unwind: Option<BasicBlock>,
+ },
+
+ /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
+ /// the referred to function. The operand types must match the argument types of the function.
+ /// The return place type must match the return type. The type of the `func` operand must be
+ /// callable, meaning either a function pointer, a function type, or a closure type.
+ ///
+ /// **Needs clarification**: The exact semantics of this. Current backends rely on `move`
+ /// operands not aliasing the return place. It is unclear how this is justified in MIR, see
+ /// [#71117].
+ ///
+ /// [#71117]: https://github.com/rust-lang/rust/issues/71117
+ 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>>,
+ /// Where the returned value will be written
+ destination: Place<'tcx>,
+ /// Where to go after this call returns. If none, the call necessarily diverges.
+ target: Option<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,
+ /// This `Span` is the span of the function, without the dot and receiver
+ /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+ fn_span: Span,
+ },
+
+ /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
+ /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
+ /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
+ /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not
+ /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
+ /// assertion does not fail, execution continues at the specified basic block.
+ Assert {
+ cond: Operand<'tcx>,
+ expected: bool,
+ msg: AssertMessage<'tcx>,
+ target: BasicBlock,
+ cleanup: Option<BasicBlock>,
+ },
+
+ /// Marks a suspend point.
+ ///
+ /// Like `Return` terminators in generator bodies, this computes `value` and then a
+ /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to
+ /// the return place of the function calling this one, and execution continues in the calling
+ /// function. When next invoked with the same first argument, execution of this function
+ /// continues at the `resume` basic block, with the second argument written to the `resume_arg`
+ /// place. If the generator is dropped before then, the `drop` basic block is invoked.
+ ///
+ /// Not permitted in bodies that are not generator bodies, or after generator lowering.
+ ///
+ /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
+ 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 dropping a generator.
+ ///
+ /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations
+ /// as `yield`.
+ ///
+ /// **Needs clarification**: Is that even correct? The generator drop code is always confusing
+ /// to me, because it's not even really in the current body.
+ ///
+ /// **Needs clarification**: Are there type system constraints on these terminators? Should
+ /// there be a "block type" like `cleanup` blocks for them?
+ GeneratorDrop,
+
+ /// A block where control flow only ever takes one real path, but borrowck needs to be more
+ /// conservative.
+ ///
+ /// At runtime this is semantically just a goto.
+ ///
+ /// Disallowed after drop elaboration.
+ FalseEdge {
+ /// 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.
+ ///
+ /// At runtime this is semantically just a goto.
+ ///
+ /// Disallowed after drop elaboration.
+ 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 `abort_unwinding_calls` passes.
+ unwind: Option<BasicBlock>,
+ },
+
+ /// Block ends with an inline assembly block. This is a terminator since
+ /// inline assembly is allowed to diverge.
+ InlineAsm {
+ /// The template for the inline assembly, with placeholders.
+ template: &'tcx [InlineAsmTemplatePiece],
+
+ /// The operands for the inline assembly, as `Operand`s or `Place`s.
+ operands: Vec<InlineAsmOperand<'tcx>>,
+
+ /// Miscellaneous options for the inline assembly.
+ options: InlineAsmOptions,
+
+ /// Source spans for each line of the inline assembly code. These are
+ /// used to map assembler errors back to the line in the source code.
+ line_spans: &'tcx [Span],
+
+ /// Destination block after the inline assembly returns, unless it is
+ /// diverging (InlineAsmOptions::NORETURN).
+ destination: Option<BasicBlock>,
+
+ /// Cleanup to be done if the inline assembly unwinds. This is present
+ /// if and only if InlineAsmOptions::MAY_UNWIND is set.
+ cleanup: Option<BasicBlock>,
+ },
+}
+
+/// Information about an assertion failure.
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+pub enum AssertKind<O> {
+ BoundsCheck { len: O, index: O },
+ Overflow(BinOp, O, O),
+ OverflowNeg(O),
+ DivisionByZero(O),
+ RemainderByZero(O),
+ ResumedAfterReturn(GeneratorKind),
+ ResumedAfterPanic(GeneratorKind),
+}
+
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum InlineAsmOperand<'tcx> {
+ In {
+ reg: InlineAsmRegOrRegClass,
+ value: Operand<'tcx>,
+ },
+ Out {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ place: Option<Place<'tcx>>,
+ },
+ InOut {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ in_value: Operand<'tcx>,
+ out_place: Option<Place<'tcx>>,
+ },
+ Const {
+ value: Box<Constant<'tcx>>,
+ },
+ SymFn {
+ value: Box<Constant<'tcx>>,
+ },
+ SymStatic {
+ def_id: DefId,
+ },
+}
+
+/// Type for MIR `Assert` terminator error messages.
+pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
+
+///////////////////////////////////////////////////////////////////////////
+// Places
+
+/// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical
+/// object as places in Rust. This of course means that what exactly they are is undecided and part
+/// of the Rust memory model. However, they will likely contain at least the following pieces of
+/// information in some form:
+///
+/// 1. The address in memory that the place refers to.
+/// 2. The provenance with which the place is being accessed.
+/// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy].
+/// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`.
+///
+/// We'll give a description below of how all pieces of the place except for the provenance are
+/// calculated. We cannot give a description of the provenance, because that is part of the
+/// undecided aliasing model - we only include it here at all to acknowledge its existence.
+///
+/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has
+/// the address of the local's allocation and the type of the local.
+///
+/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation
+/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation.
+/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under
+/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and
+/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into
+/// the current MIR semantics in a clean way - possibly this needs some design work first.
+///
+/// For places that are not locals, ie they have a non-empty list of projections, we define the
+/// values as a function of the parent place, that is the place with its last [`ProjectionElem`]
+/// stripped. The way this is computed of course depends on the kind of that last projection
+/// element:
+///
+/// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
+/// given one, and makes no other changes. A `Downcast` projection on a place with its variant
+/// index already set is not well-formed.
+/// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
+/// place referring to one of the fields of the type. The resulting address is the parent
+/// address, plus the offset of the field. The type becomes the type of the field. If the parent
+/// was unsized and so had metadata associated with it, then the metadata is retained if the
+/// field is unsized and thrown out if it is sized.
+///
+/// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or
+/// generator has more than one variant, the parent place's variant index must be set, indicating
+/// which variant is being used. If it has just one variant, the variant index may or may not be
+/// included - the single possible variant is inferred if it is not included.
+/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
+/// place as described in the documentation for the `ProjectionElem`. The resulting address is
+/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent
+/// place has type `[T; N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any
+/// resulting metadata is thrown out.
+/// - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new
+/// address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`.
+/// However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the
+/// length of the subslice.
+/// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`.
+/// However, `Index` additionally takes a local from which the value of the index is computed at
+/// runtime. Computing the value of the index involves interpreting the `Local` as a
+/// `Place { local, projection: [] }`, and then computing its value as if done via
+/// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must
+/// have type `usize`.
+/// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most
+/// complicated. They are only legal on parent places that are references, pointers, or `Box`. A
+/// `Deref` projection begins by loading a value from the parent place, as if by
+/// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the
+/// pointee's type. The resulting address is the address that was stored in the pointer. If the
+/// pointee type is unsized, the pointer additionally stored the value of the metadata.
+///
+/// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not
+/// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not
+/// point to an actual allocation.
+///
+/// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed
+/// in [UCG#319]. The options include that every place must obey those rules, that only some places
+/// must obey them, or that places impose no rules of their own.
+///
+/// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319
+///
+/// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken
+/// advantage of by codegen (via `gep inbounds`). That is possibly subject to change.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, 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>>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub enum ProjectionElem<V, T> {
+ Deref,
+ Field(Field, T),
+ /// Index into a slice/array.
+ ///
+ /// Note that this does not also dereference, and so it does not exactly correspond to slice
+ /// indexing in Rust. In other words, in the below Rust code:
+ ///
+ /// ```rust
+ /// let x = &[1, 2, 3, 4];
+ /// let i = 2;
+ /// x[i];
+ /// ```
+ ///
+ /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same
+ /// thing is true of the `ConstantIndex` and `Subslice` projections below.
+ Index(V),
+
+ /// These indices are generated by slice patterns. Easiest to explain
+ /// by example:
+ ///
+ /// ```ignore (illustrative)
+ /// [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: u64,
+ /// The thing being indexed must be at least this long. For arrays this
+ /// is always the exact length.
+ min_length: u64,
+ /// 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: u64,
+ to: u64,
+ /// 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 enum or a generator.
+ ///
+ /// The included Symbol is the name of the variant, used for printing MIR.
+ Downcast(Option<Symbol>, VariantIdx),
+}
+
+/// 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>>;
+
+///////////////////////////////////////////////////////////////////////////
+// Operands
+
+/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
+/// the memory model. One proposal for a definition of values can be found [on UCG][value-def].
+///
+/// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md
+///
+/// The most common way to create values is via loading a place. Loading a place is an operation
+/// which reads the memory of the place and converts it to a value. This is a fundamentally *typed*
+/// operation. The nature of the value produced depends on the type of the conversion. Furthermore,
+/// there may be other effects: if the type has a validity constraint loading the place might be UB
+/// if the validity constraint is not met.
+///
+/// **Needs clarification:** Ralf proposes that loading a place not have side-effects.
+/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
+/// something we can even decide without knowing more about Rust's memory model?
+///
+/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri
+/// currently implements it, but it seems like this may be something to check against in the
+/// validator.
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum Operand<'tcx> {
+ /// Creates a value by loading the given place.
+ ///
+ /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there
+ /// is no such requirement.
+ Copy(Place<'tcx>),
+
+ /// Creates a value by performing loading the place, just like the `Copy` operand.
+ ///
+ /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide
+ /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
+ /// place without first re-initializing it.
+ ///
+ /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
+ Move(Place<'tcx>),
+
+ /// Constants are already semantically values, and remain unchanged.
+ Constant(Box<Constant<'tcx>>),
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Rvalues
+
+/// The various kinds of rvalues that can appear in MIR.
+///
+/// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below.
+///
+/// Computing any rvalue begins by evaluating the places and operands in some order (**Needs
+/// clarification**: Which order?). These are then used to produce a "value" - the same kind of
+/// value that an [`Operand`] produces.
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+pub enum Rvalue<'tcx> {
+ /// Yields the operand unchanged
+ Use(Operand<'tcx>),
+
+ /// Creates an array where each element is the value of the operand.
+ ///
+ /// This is the cause of a bug in the case where the repetition count is zero because the value
+ /// is not dropped, see [#74836].
+ ///
+ /// Corresponds to source code like `[x; 32]`.
+ ///
+ /// [#74836]: https://github.com/rust-lang/rust/issues/74836
+ Repeat(Operand<'tcx>, ty::Const<'tcx>),
+
+ /// Creates a reference of the indicated kind to the place.
+ ///
+ /// There is not much to document here, because besides the obvious parts the semantics of this
+ /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing
+ /// exactly what the behavior of this operation should be.
+ ///
+ /// `Shallow` borrows are disallowed after drop lowering.
+ Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
+
+ /// Creates a pointer/reference to the given thread local.
+ ///
+ /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
+ /// `*const T`, and if neither of those apply a `&T`.
+ ///
+ /// **Note:** This is a runtime operation that actually executes code and is in this sense more
+ /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
+ /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
+ ///
+ /// **Needs clarification**: Are there weird additional semantics here related to the runtime
+ /// nature of this operation?
+ ThreadLocalRef(DefId),
+
+ /// Creates a pointer with the indicated mutability to the place.
+ ///
+ /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
+ /// `&raw v` or `addr_of!(v)`.
+ ///
+ /// Like with references, the semantics of this operation are heavily dependent on the aliasing
+ /// model.
+ AddressOf(Mutability, Place<'tcx>),
+
+ /// Yields the length of the place, as a `usize`.
+ ///
+ /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
+ /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
+ /// ill-formed for places of other types.
+ Len(Place<'tcx>),
+
+ /// Performs essentially all of the casts that can be performed via `as`.
+ ///
+ /// This allows for casts from/to a variety of types.
+ ///
+ /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
+ /// `ArrayToPointer` and `MutToConstPointer` are special.
+ Cast(CastKind, Operand<'tcx>, Ty<'tcx>),
+
+ /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
+ /// parameter may be a `usize` as well.
+ /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+ /// raw pointers, or function pointers and return a `bool`. The types of the operands must be
+ /// matching, up to the usual caveat of the lifetimes in function pointers.
+ /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+ /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+ /// truncated as needed.
+ /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+ /// types and return a value of that type.
+ /// * The remaining operations accept signed integers, unsigned integers, or floats with
+ /// matching types and return a value of that type.
+ BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
+
+ /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
+ ///
+ /// When overflow checking is disabled and we are generating run-time code, the error condition
+ /// is false. Otherwise, and always during CTFE, the error condition is determined as described
+ /// below.
+ ///
+ /// For addition, subtraction, and multiplication on integers the error condition is set when
+ /// the infinite precision result would be unequal to the actual result.
+ ///
+ /// For shift operations on integers the error condition is set when the value of right-hand
+ /// side is greater than or equal to the number of bits in the type of the left-hand side, or
+ /// when the value of right-hand side is negative.
+ ///
+ /// Other combinations of types and operators are unsupported.
+ CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
+
+ /// Computes a value as described by the operation.
+ NullaryOp(NullOp, Ty<'tcx>),
+
+ /// Exactly like `BinaryOp`, but less operands.
+ ///
+ /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
+ /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
+ /// return a value with the same type as their operand.
+ UnaryOp(UnOp, Operand<'tcx>),
+
+ /// Computes the discriminant of the place, returning it as an integer of type
+ /// [`discriminant_ty`]. Returns zero for types without discriminant.
+ ///
+ /// The validity requirements for the underlying value are undecided for this rvalue, see
+ /// [#91095]. Note too that the value of the discriminant is not the same thing as the
+ /// variant index; use [`discriminant_for_variant`] to convert.
+ ///
+ /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
+ /// [#91095]: https://github.com/rust-lang/rust/issues/91095
+ /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
+ Discriminant(Place<'tcx>),
+
+ /// Creates an aggregate value, like a tuple or struct.
+ ///
+ /// This is needed because dataflow analysis needs to distinguish
+ /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
+ /// has a destructor.
+ ///
+ /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
+ /// generator lowering, `Generator` aggregate kinds are disallowed too.
+ Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
+
+ /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
+ ///
+ /// This is different from a normal transmute because dataflow analysis will treat the box as
+ /// initialized but its content as uninitialized. Like other pointer casts, this in general
+ /// affects alias analysis.
+ ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
+
+ /// A CopyForDeref is equivalent to a read from a place at the
+ /// codegen level, but is treated specially by drop elaboration. When such a read happens, it
+ /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)
+ /// that the only use of the returned value is a deref operation, immediately
+ /// followed by one or more projections. Drop elaboration treats this rvalue as if the
+ /// read never happened and just projects further. This allows simplifying various MIR
+ /// optimizations and codegen backends that previously had to handle deref operations anywhere
+ /// in a place.
+ CopyForDeref(Place<'tcx>),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum CastKind {
+ /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
+ /// between a function pointer and an integer type.
+ /// See the docs on `expose_addr` for more details.
+ PointerExposeAddress,
+ /// An address-to-pointer cast that picks up an exposed provenance.
+ /// See the docs on `from_exposed_addr` for more details.
+ PointerFromExposedAddress,
+ /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
+ /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
+ Pointer(PointerCast),
+ /// Remaining unclassified casts.
+ Misc,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, 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(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>),
+
+ // Note: We can use LocalDefId since closures and generators a deaggregated
+ // before codegen.
+ Closure(LocalDefId, SubstsRef<'tcx>),
+ Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability),
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum NullOp {
+ /// Returns the size of a value of that type
+ SizeOf,
+ /// Returns the minimum alignment of a type
+ AlignOf,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum UnOp {
+ /// The `!` operator for logical inversion
+ Not,
+ /// The `-` operator for negation
+ Neg,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum BinOp {
+ /// The `+` operator (addition)
+ Add,
+ /// The `-` operator (subtraction)
+ Sub,
+ /// The `*` operator (multiplication)
+ Mul,
+ /// The `/` operator (division)
+ ///
+ /// Division by zero is UB, because the compiler should have inserted checks
+ /// prior to this.
+ Div,
+ /// The `%` operator (modulus)
+ ///
+ /// Using zero as the modulus (second operand) is UB, because the compiler
+ /// should have inserted checks prior to this.
+ Rem,
+ /// The `^` operator (bitwise xor)
+ BitXor,
+ /// The `&` operator (bitwise and)
+ BitAnd,
+ /// The `|` operator (bitwise or)
+ BitOr,
+ /// The `<<` operator (shift left)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
+ Shl,
+ /// The `>>` operator (shift right)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
+ 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,
+}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(AggregateKind<'_>, 48);
+ static_assert_size!(Operand<'_>, 24);
+ static_assert_size!(Place<'_>, 16);
+ static_assert_size!(PlaceElem<'_>, 24);
+ static_assert_size!(Rvalue<'_>, 40);
+}
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
new file mode 100644
index 000000000..405003156
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -0,0 +1,307 @@
+/*!
+ * Methods for the various MIR types. These are intended for use after
+ * building is complete.
+ */
+
+use crate::mir::*;
+use crate::ty::subst::Subst;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_hir as hir;
+use rustc_target::abi::VariantIdx;
+
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+pub struct PlaceTy<'tcx> {
+ pub ty: Ty<'tcx>,
+ /// Downcast to a particular variant of an enum or a generator, if included.
+ pub variant_index: Option<VariantIdx>,
+}
+
+// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(PlaceTy<'_>, 16);
+
+impl<'tcx> PlaceTy<'tcx> {
+ #[inline]
+ 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.variant(variant_index)
+ }
+ };
+ let field_def = &variant_def.fields[f.index()];
+ field_def.ty(tcx, substs)
+ }
+ ty::Tuple(tys) => tys[f.index()],
+ _ => 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 + Copy,
+ {
+ if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
+ bug!("cannot use non field projection on downcasted place")
+ }
+ 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(f, 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)
+ }
+}
+
+impl<'tcx> PlaceRef<'tcx> {
+ 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_ty(ty::Array(operand.ty(local_decls, tcx), count))
+ }
+ Rvalue::ThreadLocalRef(did) => {
+ let static_ty = tcx.type_of(did);
+ if tcx.is_mutable_static(did) {
+ tcx.mk_mut_ptr(static_ty)
+ } else if tcx.is_foreign_item(did) {
+ tcx.mk_imm_ptr(static_ty)
+ } else {
+ // FIXME: These things don't *really* have 'static lifetime.
+ tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty)
+ }
+ }
+ 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 })
+ }
+ Rvalue::Len(..) => tcx.types.usize,
+ Rvalue::Cast(.., ty) => ty,
+ Rvalue::BinaryOp(op, box (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, box (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 | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
+ Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
+ Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => 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(did, _, substs, _, _) => {
+ tcx.bound_type_of(did).subst(tcx, substs)
+ }
+ AggregateKind::Closure(did, substs) => tcx.mk_closure(did.to_def_id(), substs),
+ AggregateKind::Generator(did, substs, movability) => {
+ tcx.mk_generator(did.to_def_id(), substs, movability)
+ }
+ },
+ Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
+ Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
+ }
+ }
+
+ #[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::ShallowInitBox(_, _) => 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 a `&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/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
new file mode 100644
index 000000000..9ccf5aea6
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -0,0 +1,448 @@
+use crate::mir;
+use crate::mir::interpret::Scalar;
+use crate::ty::{self, Ty, TyCtxt};
+use smallvec::{smallvec, SmallVec};
+
+use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind};
+use rustc_ast::InlineAsmTemplatePiece;
+pub use rustc_ast::Mutability;
+use rustc_macros::HashStable;
+use std::borrow::Cow;
+use std::fmt::{self, Debug, Formatter, Write};
+use std::iter;
+use std::slice;
+
+pub use super::query::*;
+
+#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+pub struct SwitchTargets {
+ /// Possible values. The locations to branch to in each case
+ /// are found in the corresponding indices from the `targets` vector.
+ values: SmallVec<[u128; 1]>,
+
+ /// 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: SmallVec<[BasicBlock; 2]>,
+}
+
+impl SwitchTargets {
+ /// Creates switch targets from an iterator of values and target blocks.
+ ///
+ /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
+ /// `goto otherwise;`.
+ pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
+ let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
+ targets.push(otherwise);
+ Self { values, targets }
+ }
+
+ /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
+ /// and to `else_` if not.
+ pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
+ Self { values: smallvec![value], targets: smallvec![then, else_] }
+ }
+
+ /// Returns the fallback target that is jumped to when none of the values match the operand.
+ pub fn otherwise(&self) -> BasicBlock {
+ *self.targets.last().unwrap()
+ }
+
+ /// Returns an iterator over the switch targets.
+ ///
+ /// The iterator will yield tuples containing the value and corresponding target to jump to, not
+ /// including the `otherwise` fallback target.
+ ///
+ /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
+ pub fn iter(&self) -> SwitchTargetsIter<'_> {
+ SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) }
+ }
+
+ /// Returns a slice with all possible jump targets (including the fallback target).
+ pub fn all_targets(&self) -> &[BasicBlock] {
+ &self.targets
+ }
+
+ pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
+ &mut self.targets
+ }
+
+ /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
+ /// specific value. This cannot fail, as it'll return the `otherwise`
+ /// branch if there's not a specific match for the value.
+ pub fn target_for_value(&self, value: u128) -> BasicBlock {
+ self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
+ }
+}
+
+pub struct SwitchTargetsIter<'a> {
+ inner: iter::Zip<slice::Iter<'a, u128>, slice::Iter<'a, BasicBlock>>,
+}
+
+impl<'a> Iterator for SwitchTargetsIter<'a> {
+ type Item = (u128, BasicBlock);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next().map(|(val, bb)| (*val, *bb))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct Terminator<'tcx> {
+ pub source_info: SourceInfo,
+ pub kind: TerminatorKind<'tcx>,
+}
+
+pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a;
+pub type SuccessorsMut<'a> =
+ iter::Chain<std::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> {
+ TerminatorKind::SwitchInt {
+ discr: cond,
+ switch_ty: tcx.types.bool,
+ targets: SwitchTargets::static_if(0, f, t),
+ }
+ }
+
+ pub fn successors(&self) -> Successors<'_> {
+ use self::TerminatorKind::*;
+ match *self {
+ Resume
+ | Abort
+ | GeneratorDrop
+ | Return
+ | Unreachable
+ | Call { target: None, cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: None, .. } => {
+ None.into_iter().chain((&[]).into_iter().copied())
+ }
+ Goto { target: t }
+ | Call { target: None, cleanup: Some(t), .. }
+ | Call { target: Some(t), cleanup: None, .. }
+ | Yield { resume: t, drop: None, .. }
+ | DropAndReplace { target: t, unwind: None, .. }
+ | Drop { target: t, unwind: None, .. }
+ | Assert { target: t, cleanup: None, .. }
+ | FalseUnwind { real_target: t, unwind: None }
+ | InlineAsm { destination: Some(t), cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: Some(t), .. } => {
+ Some(t).into_iter().chain((&[]).into_iter().copied())
+ }
+ Call { target: Some(t), cleanup: Some(ref u), .. }
+ | Yield { resume: t, drop: Some(ref u), .. }
+ | DropAndReplace { target: t, unwind: Some(ref u), .. }
+ | Drop { target: t, unwind: Some(ref u), .. }
+ | Assert { target: t, cleanup: Some(ref u), .. }
+ | FalseUnwind { real_target: t, unwind: Some(ref u) }
+ | InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => {
+ Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
+ }
+ SwitchInt { ref targets, .. } => {
+ None.into_iter().chain(targets.targets.iter().copied())
+ }
+ FalseEdge { real_target, ref imaginary_target } => Some(real_target)
+ .into_iter()
+ .chain(slice::from_ref(imaginary_target).into_iter().copied()),
+ }
+ }
+
+ pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
+ use self::TerminatorKind::*;
+ match *self {
+ Resume
+ | Abort
+ | GeneratorDrop
+ | Return
+ | Unreachable
+ | Call { target: None, cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
+ Goto { target: ref mut t }
+ | Call { target: None, cleanup: Some(ref mut t), .. }
+ | Call { target: 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 }
+ | InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
+ Some(t).into_iter().chain(&mut [])
+ }
+ Call { target: 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) }
+ | InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
+ Some(t).into_iter().chain(slice::from_mut(u))
+ }
+ SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
+ FalseEdge { 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::FalseEdge { .. } => None,
+ TerminatorKind::Call { cleanup: ref unwind, .. }
+ | TerminatorKind::Assert { cleanup: ref unwind, .. }
+ | TerminatorKind::DropAndReplace { ref unwind, .. }
+ | TerminatorKind::Drop { ref unwind, .. }
+ | TerminatorKind::FalseUnwind { ref unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: 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::FalseEdge { .. } => 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, .. }
+ | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
+ }
+ }
+
+ pub fn as_switch(&self) -> Option<(&Operand<'tcx>, Ty<'tcx>, &SwitchTargets)> {
+ match self {
+ TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
+ Some((discr, *switch_ty, targets))
+ }
+ _ => None,
+ }
+ }
+
+ pub fn as_goto(&self) -> Option<BasicBlock> {
+ match self {
+ TerminatorKind::Goto { target } => Some(*target),
+ _ => None,
+ }
+ }
+}
+
+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().next().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 { place, .. } => write!(fmt, "drop({:?})", place),
+ DropAndReplace { place, value, .. } => {
+ write!(fmt, "replace({:?} <- {:?})", place, value)
+ }
+ Call { func, args, 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.fmt_assert_args(fmt)?;
+ write!(fmt, ")")
+ }
+ FalseEdge { .. } => write!(fmt, "falseEdge"),
+ FalseUnwind { .. } => write!(fmt, "falseUnwind"),
+ InlineAsm { template, ref operands, options, .. } => {
+ write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
+ for op in operands {
+ write!(fmt, ", ")?;
+ let print_late = |&late| if late { "late" } else { "" };
+ match op {
+ InlineAsmOperand::In { reg, value } => {
+ write!(fmt, "in({}) {:?}", reg, value)?;
+ }
+ InlineAsmOperand::Out { reg, late, place: Some(place) } => {
+ write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
+ }
+ InlineAsmOperand::Out { reg, late, place: None } => {
+ write!(fmt, "{}out({}) _", print_late(late), reg)?;
+ }
+ InlineAsmOperand::InOut {
+ reg,
+ late,
+ in_value,
+ out_place: Some(out_place),
+ } => {
+ write!(
+ fmt,
+ "in{}out({}) {:?} => {:?}",
+ print_late(late),
+ reg,
+ in_value,
+ out_place
+ )?;
+ }
+ InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
+ write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
+ }
+ InlineAsmOperand::Const { value } => {
+ write!(fmt, "const {:?}", value)?;
+ }
+ InlineAsmOperand::SymFn { value } => {
+ write!(fmt, "sym_fn {:?}", value)?;
+ }
+ InlineAsmOperand::SymStatic { def_id } => {
+ write!(fmt, "sym_static {:?}", def_id)?;
+ }
+ }
+ }
+ write!(fmt, ", options({:?}))", options)
+ }
+ }
+ }
+
+ /// 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 targets, 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;
+ targets
+ .values
+ .iter()
+ .map(|&u| {
+ mir::ConstantKind::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
+ .to_string()
+ .into()
+ })
+ .chain(iter::once("otherwise".into()))
+ .collect()
+ }),
+ Call { target: Some(_), cleanup: Some(_), .. } => {
+ vec!["return".into(), "unwind".into()]
+ }
+ Call { target: Some(_), cleanup: None, .. } => vec!["return".into()],
+ Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+ Call { target: 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()],
+ FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
+ FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
+ FalseUnwind { unwind: None, .. } => vec!["real".into()],
+ InlineAsm { destination: Some(_), cleanup: Some(_), .. } => {
+ vec!["return".into(), "unwind".into()]
+ }
+ InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
+ InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+ InlineAsm { destination: None, cleanup: None, .. } => vec![],
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
new file mode 100644
index 000000000..627dc32f3
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -0,0 +1,388 @@
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_index::bit_set::BitSet;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+use super::*;
+
+/// Preorder traversal of a graph.
+///
+/// Preorder traversal is when each node is visited after at least one of its predecessors. If you
+/// are familiar with some basic graph theory, then this performs a depth first search and returns
+/// nodes in order of discovery time.
+///
+/// ```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. If you are familiar with some basic graph theory,
+/// then this performs a depth first search and returns nodes in order of completion time.
+///
+///
+/// ```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> {
+ basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+ visited: BitSet<BasicBlock>,
+ visit_stack: Vec<(BasicBlock, Successors<'a>)>,
+ root_is_start_block: bool,
+}
+
+impl<'a, 'tcx> Postorder<'a, 'tcx> {
+ pub fn new(
+ basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+ root: BasicBlock,
+ ) -> Postorder<'a, 'tcx> {
+ let mut po = Postorder {
+ basic_blocks,
+ visited: BitSet::new_empty(basic_blocks.len()),
+ visit_stack: Vec::new(),
+ root_is_start_block: root == START_BLOCK,
+ };
+
+ let data = &po.basic_blocks[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.basic_blocks[bb].terminator {
+ self.visit_stack.push((bb, term.successors()));
+ }
+ }
+ }
+ }
+}
+
+pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
+ Postorder::new(&body.basic_blocks, 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.basic_blocks[bb]))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ // All the blocks, minus the number of blocks we've visited.
+ let upper = self.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.basic_blocks, root).map(|(bb, _)| bb).collect();
+ let len = blocks.len();
+ ReversePostorder { body, blocks, idx: len }
+ }
+}
+
+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> {}
+
+/// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular
+/// order.
+///
+/// This is clearer than writing `preorder` in cases where the order doesn't matter.
+pub fn reachable<'a, 'tcx>(
+ body: &'a Body<'tcx>,
+) -> impl 'a + Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
+ preorder(body)
+}
+
+/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
+pub fn reachable_as_bitset<'tcx>(body: &Body<'tcx>) -> BitSet<BasicBlock> {
+ let mut iter = preorder(body);
+ (&mut iter).for_each(drop);
+ iter.visited
+}
+
+#[derive(Clone)]
+pub struct ReversePostorderIter<'a, 'tcx> {
+ body: &'a Body<'tcx>,
+ blocks: &'a [BasicBlock],
+ idx: usize,
+}
+
+impl<'a, 'tcx> Iterator for ReversePostorderIter<'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 ReversePostorderIter<'a, 'tcx> {}
+
+pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> {
+ let blocks = body.basic_blocks.postorder();
+ let len = blocks.len();
+ ReversePostorderIter { body, blocks, idx: len }
+}
+
+#[derive(Clone, Debug)]
+pub(super) struct PostorderCache {
+ cache: OnceCell<Vec<BasicBlock>>,
+}
+
+impl PostorderCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ PostorderCache { cache: OnceCell::new() }
+ }
+
+ /// Invalidates the postorder cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ self.cache = OnceCell::new();
+ }
+
+ /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR.
+ #[inline]
+ pub(super) fn compute(&self, body: &IndexVec<BasicBlock, BasicBlockData<'_>>) -> &[BasicBlock] {
+ self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
+ }
+}
+
+impl<S: Encoder> Encodable<S> for PostorderCache {
+ #[inline]
+ fn encode(&self, _s: &mut S) {}
+}
+
+impl<D: Decoder> Decodable<D> for PostorderCache {
+ #[inline]
+ fn decode(_: &mut D) -> Self {
+ Self::new()
+ }
+}
+
+impl<CTX> HashStable<CTX> for PostorderCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ PostorderCache,
+}
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
new file mode 100644
index 000000000..82a6b0c50
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -0,0 +1,240 @@
+//! `TypeFoldable` implementations for MIR types
+
+use super::*;
+use crate::ty;
+use rustc_data_structures::functor::IdFunctor;
+
+TrivialTypeTraversalAndLiftImpls! {
+ BlockTailInfo,
+ MirPhase,
+ SourceInfo,
+ FakeReadCause,
+ RetagKind,
+ SourceScope,
+ SourceScopeLocalData,
+ UserTypeAnnotationIndex,
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ use crate::mir::TerminatorKind::*;
+
+ let kind = match self.kind {
+ Goto { target } => Goto { target },
+ SwitchInt { discr, switch_ty, targets } => SwitchInt {
+ discr: discr.try_fold_with(folder)?,
+ switch_ty: switch_ty.try_fold_with(folder)?,
+ targets,
+ },
+ Drop { place, target, unwind } => {
+ Drop { place: place.try_fold_with(folder)?, target, unwind }
+ }
+ DropAndReplace { place, value, target, unwind } => DropAndReplace {
+ place: place.try_fold_with(folder)?,
+ value: value.try_fold_with(folder)?,
+ target,
+ unwind,
+ },
+ Yield { value, resume, resume_arg, drop } => Yield {
+ value: value.try_fold_with(folder)?,
+ resume,
+ resume_arg: resume_arg.try_fold_with(folder)?,
+ drop,
+ },
+ Call { func, args, destination, target, cleanup, from_hir_call, fn_span } => Call {
+ func: func.try_fold_with(folder)?,
+ args: args.try_fold_with(folder)?,
+ destination: destination.try_fold_with(folder)?,
+ target,
+ cleanup,
+ from_hir_call,
+ fn_span,
+ },
+ Assert { cond, expected, msg, target, cleanup } => {
+ use AssertKind::*;
+ let msg = match msg {
+ BoundsCheck { len, index } => BoundsCheck {
+ len: len.try_fold_with(folder)?,
+ index: index.try_fold_with(folder)?,
+ },
+ Overflow(op, l, r) => {
+ Overflow(op, l.try_fold_with(folder)?, r.try_fold_with(folder)?)
+ }
+ OverflowNeg(op) => OverflowNeg(op.try_fold_with(folder)?),
+ DivisionByZero(op) => DivisionByZero(op.try_fold_with(folder)?),
+ RemainderByZero(op) => RemainderByZero(op.try_fold_with(folder)?),
+ ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
+ };
+ Assert { cond: cond.try_fold_with(folder)?, expected, msg, target, cleanup }
+ }
+ GeneratorDrop => GeneratorDrop,
+ Resume => Resume,
+ Abort => Abort,
+ Return => Return,
+ Unreachable => Unreachable,
+ FalseEdge { real_target, imaginary_target } => {
+ FalseEdge { real_target, imaginary_target }
+ }
+ FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
+ InlineAsm { template, operands, options, line_spans, destination, cleanup } => {
+ InlineAsm {
+ template,
+ operands: operands.try_fold_with(folder)?,
+ options,
+ line_spans,
+ destination,
+ cleanup,
+ }
+ }
+ };
+ Ok(Terminator { source_info: self.source_info, kind })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(Place {
+ local: self.local.try_fold_with(folder)?,
+ projection: self.projection.try_fold_with(folder)?,
+ })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ use crate::mir::Rvalue::*;
+ Ok(match self {
+ Use(op) => Use(op.try_fold_with(folder)?),
+ Repeat(op, len) => Repeat(op.try_fold_with(folder)?, len.try_fold_with(folder)?),
+ ThreadLocalRef(did) => ThreadLocalRef(did.try_fold_with(folder)?),
+ Ref(region, bk, place) => {
+ Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?)
+ }
+ CopyForDeref(place) => CopyForDeref(place.try_fold_with(folder)?),
+ AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?),
+ Len(place) => Len(place.try_fold_with(folder)?),
+ Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?),
+ BinaryOp(op, box (rhs, lhs)) => {
+ BinaryOp(op, Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)))
+ }
+ CheckedBinaryOp(op, box (rhs, lhs)) => CheckedBinaryOp(
+ op,
+ Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)),
+ ),
+ UnaryOp(op, val) => UnaryOp(op, val.try_fold_with(folder)?),
+ Discriminant(place) => Discriminant(place.try_fold_with(folder)?),
+ NullaryOp(op, ty) => NullaryOp(op, ty.try_fold_with(folder)?),
+ Aggregate(kind, fields) => {
+ let kind = kind.try_map_id(|kind| {
+ Ok(match kind {
+ AggregateKind::Array(ty) => AggregateKind::Array(ty.try_fold_with(folder)?),
+ AggregateKind::Tuple => AggregateKind::Tuple,
+ AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+ def,
+ v,
+ substs.try_fold_with(folder)?,
+ user_ty.try_fold_with(folder)?,
+ n,
+ ),
+ AggregateKind::Closure(id, substs) => {
+ AggregateKind::Closure(id, substs.try_fold_with(folder)?)
+ }
+ AggregateKind::Generator(id, substs, movablity) => {
+ AggregateKind::Generator(id, substs.try_fold_with(folder)?, movablity)
+ }
+ })
+ })?;
+ Aggregate(kind, fields.try_fold_with(folder)?)
+ }
+ ShallowInitBox(op, ty) => {
+ ShallowInitBox(op.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(match self {
+ Operand::Copy(place) => Operand::Copy(place.try_fold_with(folder)?),
+ Operand::Move(place) => Operand::Move(place.try_fold_with(folder)?),
+ Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?),
+ })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ use crate::mir::ProjectionElem::*;
+
+ Ok(match self {
+ Deref => Deref,
+ Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
+ Index(v) => Index(v.try_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 },
+ })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Field {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(Constant {
+ span: self.span,
+ user_ty: self.user_ty.try_fold_with(folder)?,
+ literal: self.literal.try_fold_with(folder)?,
+ })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
+ #[inline(always)]
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_mir_const(self)
+ }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ match self {
+ ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)),
+ ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
new file mode 100644
index 000000000..6a0801cb0
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -0,0 +1,190 @@
+//! `TypeVisitable` implementations for MIR types
+
+use super::*;
+use crate::ty;
+
+impl<'tcx> TypeVisitable<'tcx> for Terminator<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ use crate::mir::TerminatorKind::*;
+
+ match self.kind {
+ SwitchInt { ref discr, switch_ty, .. } => {
+ discr.visit_with(visitor)?;
+ switch_ty.visit_with(visitor)
+ }
+ Drop { ref place, .. } => place.visit_with(visitor),
+ DropAndReplace { ref place, ref value, .. } => {
+ place.visit_with(visitor)?;
+ value.visit_with(visitor)
+ }
+ Yield { ref value, .. } => value.visit_with(visitor),
+ Call { ref func, ref args, ref destination, .. } => {
+ destination.visit_with(visitor)?;
+ func.visit_with(visitor)?;
+ args.visit_with(visitor)
+ }
+ Assert { ref cond, ref msg, .. } => {
+ cond.visit_with(visitor)?;
+ use AssertKind::*;
+ match msg {
+ BoundsCheck { ref len, ref index } => {
+ len.visit_with(visitor)?;
+ index.visit_with(visitor)
+ }
+ Overflow(_, l, r) => {
+ l.visit_with(visitor)?;
+ r.visit_with(visitor)
+ }
+ OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+ op.visit_with(visitor)
+ }
+ ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
+ }
+ }
+ InlineAsm { ref operands, .. } => operands.visit_with(visitor),
+ Goto { .. }
+ | Resume
+ | Abort
+ | Return
+ | GeneratorDrop
+ | Unreachable
+ | FalseEdge { .. }
+ | FalseUnwind { .. } => ControlFlow::CONTINUE,
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for GeneratorKind {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Place<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.local.visit_with(visitor)?;
+ self.projection.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Rvalue<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ use crate::mir::Rvalue::*;
+ match *self {
+ Use(ref op) => op.visit_with(visitor),
+ CopyForDeref(ref place) => {
+ let op = &Operand::Copy(*place);
+ op.visit_with(visitor)
+ }
+ Repeat(ref op, _) => op.visit_with(visitor),
+ ThreadLocalRef(did) => did.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(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (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 => {}
+ 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)
+ }
+ ShallowInitBox(ref op, ty) => {
+ op.visit_with(visitor)?;
+ ty.visit_with(visitor)
+ }
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Operand<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ match *self {
+ Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
+ Operand::Constant(ref c) => c.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for PlaceElem<'tcx> {
+ fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
+ use crate::mir::ProjectionElem::*;
+
+ match self {
+ Field(_, ty) => ty.visit_with(visitor),
+ Index(v) => v.visit_with(visitor),
+ _ => ControlFlow::CONTINUE,
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Field {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for GeneratorSavedLocal {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Constant<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.literal.visit_with(visitor)?;
+ self.user_ty.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_mir_const(*self)
+ }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ match *self {
+ ConstantKind::Ty(c) => c.visit_with(visitor),
+ ConstantKind::Val(_, t) => t.visit_with(visitor),
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
new file mode 100644
index 000000000..891608764
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -0,0 +1,1330 @@
+//! # 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:
+//!
+//! ```ignore (pseudo-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.
+
+use crate::mir::*;
+use crate::ty::subst::SubstsRef;
+use crate::ty::{CanonicalUserTypeAnnotation, Ty};
+use rustc_span::Span;
+
+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: &$($mutability)? Body<'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<'tcx>,
+ ) {
+ 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_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_coverage(
+ &mut self,
+ coverage: & $($mutability)? Coverage,
+ location: Location,
+ ) {
+ self.super_coverage(coverage, 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);
+ }
+
+ 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)? 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,
+ body: &$($mutability)? Body<'tcx>,
+ ) {
+ let span = body.span;
+ if let Some(gen) = &$($mutability)? body.generator {
+ if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
+ self.visit_ty(
+ yield_ty,
+ TyContext::YieldTy(SourceInfo::outermost(span))
+ );
+ }
+ }
+
+ // for best performance, we want to use an iterator rather
+ // than a for-loop, to avoid calling `body::Body::invalidate` for
+ // each basic block.
+ #[allow(unused_macro_rules)]
+ 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);
+ }
+
+ for scope in &$($mutability)? body.source_scopes {
+ self.visit_source_scope_data(scope);
+ }
+
+ self.visit_ty(
+ $(& $mutability)? body.return_ty(),
+ TyContext::ReturnTy(SourceInfo::outermost(body.span))
+ );
+
+ for local in body.local_decls.indices() {
+ self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
+ }
+
+ #[allow(unused_macro_rules)]
+ 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);
+
+ for const_ in &$($mutability)? body.required_consts {
+ let location = START_BLOCK.start_location();
+ self.visit_constant(const_, location);
+ }
+ }
+
+ 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, statement_index: index };
+ self.visit_statement(statement, location);
+ index += 1;
+ }
+
+ if let Some(terminator) = terminator {
+ let location = Location { block, statement_index: index };
+ self.visit_terminator(terminator, location);
+ }
+ }
+
+ fn super_source_scope_data(
+ &mut self,
+ scope_data: & $($mutability)? SourceScopeData<'tcx>,
+ ) {
+ let SourceScopeData {
+ span,
+ parent_scope,
+ inlined,
+ inlined_parent_scope,
+ local_data: _,
+ } = scope_data;
+
+ self.visit_span($(& $mutability)? *span);
+ if let Some(parent_scope) = parent_scope {
+ self.visit_source_scope($(& $mutability)? *parent_scope);
+ }
+ if let Some((callee, callsite_span)) = inlined {
+ let location = START_BLOCK.start_location();
+
+ self.visit_span($(& $mutability)? *callsite_span);
+
+ let ty::Instance { def: callee_def, substs: callee_substs } = callee;
+ match callee_def {
+ ty::InstanceDef::Item(_def_id) => {}
+
+ ty::InstanceDef::Intrinsic(_def_id) |
+ ty::InstanceDef::VTableShim(_def_id) |
+ ty::InstanceDef::ReifyShim(_def_id) |
+ ty::InstanceDef::Virtual(_def_id, _) |
+ ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
+ ty::InstanceDef::DropGlue(_def_id, None) => {}
+
+ ty::InstanceDef::FnPtrShim(_def_id, ty) |
+ ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
+ ty::InstanceDef::CloneShim(_def_id, ty) => {
+ // FIXME(eddyb) use a better `TyContext` here.
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
+ }
+ }
+ self.visit_substs(callee_substs, location);
+ }
+ if let Some(inlined_parent_scope) = inlined_parent_scope {
+ self.visit_source_scope($(& $mutability)? *inlined_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 (place, rvalue)
+ ) => {
+ self.visit_assign(place, rvalue, location);
+ }
+ StatementKind::FakeRead(box (_, place)) => {
+ self.visit_place(
+ place,
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
+ location
+ );
+ }
+ StatementKind::SetDiscriminant { place, .. } => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant),
+ location
+ );
+ }
+ StatementKind::Deinit(place) => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::Deinit),
+ location
+ )
+ }
+ StatementKind::StorageLive(local) => {
+ self.visit_local(
+ $(& $mutability)? *local,
+ PlaceContext::NonUse(NonUseContext::StorageLive),
+ location
+ );
+ }
+ StatementKind::StorageDead(local) => {
+ self.visit_local(
+ $(& $mutability)? *local,
+ PlaceContext::NonUse(NonUseContext::StorageDead),
+ location
+ );
+ }
+ StatementKind::Retag(kind, place) => {
+ self.visit_retag($(& $mutability)? *kind, place, location);
+ }
+ StatementKind::AscribeUserType(
+ box (place, user_ty),
+ variance
+ ) => {
+ self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location);
+ }
+ StatementKind::Coverage(coverage) => {
+ self.visit_coverage(
+ coverage,
+ location
+ )
+ }
+ StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
+ src,
+ dst,
+ count,
+ }) => {
+ self.visit_operand(src, location);
+ self.visit_operand(dst, location);
+ self.visit_operand(count, 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);
+ match kind {
+ TerminatorKind::Goto { .. } |
+ TerminatorKind::Resume |
+ TerminatorKind::Abort |
+ TerminatorKind::GeneratorDrop |
+ TerminatorKind::Unreachable |
+ TerminatorKind::FalseEdge { .. } |
+ TerminatorKind::FalseUnwind { .. } => {}
+
+ TerminatorKind::Return => {
+ // `return` logically moves from the return place `_0`. Note that the place
+ // cannot be changed by any visitor, though.
+ let $($mutability)? local = RETURN_PLACE;
+ self.visit_local(
+ $(& $mutability)? local,
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
+ location,
+ );
+
+ assert_eq!(
+ local,
+ RETURN_PLACE,
+ "`MutVisitor` tried to mutate return place of `return` terminator"
+ );
+ }
+
+ TerminatorKind::SwitchInt {
+ discr,
+ switch_ty,
+ targets: _
+ } => {
+ self.visit_operand(discr, location);
+ self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location));
+ }
+
+ TerminatorKind::Drop {
+ place,
+ target: _,
+ unwind: _,
+ } => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::Drop),
+ location
+ );
+ }
+
+ TerminatorKind::DropAndReplace {
+ place,
+ value,
+ target: _,
+ unwind: _,
+ } => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::Drop),
+ location
+ );
+ self.visit_operand(value, location);
+ }
+
+ TerminatorKind::Call {
+ func,
+ args,
+ destination,
+ target: _,
+ cleanup: _,
+ from_hir_call: _,
+ fn_span: _
+ } => {
+ self.visit_operand(func, location);
+ for arg in args {
+ self.visit_operand(arg, location);
+ }
+ self.visit_place(
+ destination,
+ PlaceContext::MutatingUse(MutatingUseContext::Call),
+ location
+ );
+ }
+
+ TerminatorKind::Assert {
+ cond,
+ expected: _,
+ msg,
+ target: _,
+ cleanup: _,
+ } => {
+ self.visit_operand(cond, location);
+ self.visit_assert_message(msg, location);
+ }
+
+ TerminatorKind::Yield {
+ value,
+ resume: _,
+ resume_arg,
+ drop: _,
+ } => {
+ self.visit_operand(value, location);
+ self.visit_place(
+ resume_arg,
+ PlaceContext::MutatingUse(MutatingUseContext::Yield),
+ location,
+ );
+ }
+
+ TerminatorKind::InlineAsm {
+ template: _,
+ operands,
+ options: _,
+ line_spans: _,
+ destination: _,
+ cleanup: _,
+ } => {
+ for op in operands {
+ match op {
+ InlineAsmOperand::In { value, .. } => {
+ self.visit_operand(value, location);
+ }
+ InlineAsmOperand::Out { place: Some(place), .. } => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
+ location,
+ );
+ }
+ InlineAsmOperand::InOut { in_value, out_place, .. } => {
+ self.visit_operand(in_value, location);
+ if let Some(out_place) = out_place {
+ self.visit_place(
+ out_place,
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
+ location,
+ );
+ }
+ }
+ InlineAsmOperand::Const { value }
+ | InlineAsmOperand::SymFn { value } => {
+ self.visit_constant(value, location);
+ }
+ InlineAsmOperand::Out { place: None, .. }
+ | InlineAsmOperand::SymStatic { def_id: _ } => {}
+ }
+ }
+ }
+ }
+ }
+
+ 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(_, l, r) => {
+ self.visit_operand(l, location);
+ self.visit_operand(r, location);
+ }
+ OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+ self.visit_operand(op, location);
+ }
+ 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::ThreadLocalRef(_) => {}
+
+ Rvalue::Ref(r, bk, path) => {
+ self.visit_region($(& $mutability)? *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::CopyForDeref(place) => {
+ self.visit_place(
+ place,
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
+ 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($(& $mutability)? *ty, TyContext::Location(location));
+ }
+
+ Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
+ | Rvalue::CheckedBinaryOp(_bin_op, box(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($(& $mutability)? *ty, TyContext::Location(location));
+ }
+
+ Rvalue::Aggregate(kind, operands) => {
+ let kind = &$($mutability)? **kind;
+ match kind {
+ AggregateKind::Array(ty) => {
+ self.visit_ty($(& $mutability)? *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);
+ }
+ }
+
+ Rvalue::ShallowInitBox(operand, ty) => {
+ self.visit_operand(operand, location);
+ self.visit_ty($(& $mutability)? *ty, TyContext::Location(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_coverage(&mut self,
+ _coverage: & $($mutability)? Coverage,
+ _location: Location) {
+ }
+
+ 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_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($(& $mutability)? *ty, TyContext::LocalDecl {
+ local,
+ source_info: *source_info,
+ });
+ if let Some(user_ty) = user_ty {
+ 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,
+ value,
+ } = var_debug_info;
+
+ self.visit_source_info(source_info);
+ let location = START_BLOCK.start_location();
+ match value {
+ VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
+ VarDebugInfoContents::Place(place) =>
+ 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($(& $mutability)? *span);
+ drop(user_ty); // no visit method for this
+ match literal {
+ ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location),
+ ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(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($(& $mutability)? *span);
+ self.visit_source_scope($(& $mutability)? *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)? ty::Const<'tcx>) {
+ }
+
+ fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
+ }
+
+ // Convenience methods
+
+ fn visit_location(
+ &mut self,
+ body: &$($mutability)? Body<'tcx>,
+ location: Location
+ ) {
+ #[allow(unused_macro_rules)]
+ macro_rules! basic_blocks {
+ (mut) => (body.basic_blocks_mut());
+ () => (body.basic_blocks());
+ }
+ let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[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_local(&mut place.local, context, location);
+
+ if let Some(new_projection) = self.process_projection(&place.projection, location) {
+ place.projection = self.tcx().intern_place_elems(&new_projection);
+ }
+ }
+
+ fn process_projection<'a>(
+ &mut self,
+ projection: &'a [PlaceElem<'tcx>],
+ location: Location,
+ ) -> 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, location) {
+ // 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>,
+ location: Location,
+ ) -> Option<PlaceElem<'tcx>> {
+ match elem {
+ PlaceElem::Index(local) => {
+ let mut new_local = local;
+ self.visit_local(
+ &mut new_local,
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+ location,
+ );
+
+ if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
+ }
+ PlaceElem::Field(field, ty) => {
+ let mut new_ty = ty;
+ self.visit_ty(&mut new_ty, TyContext::Location(location));
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
+ PlaceElem::Deref
+ | PlaceElem::ConstantIndex { .. }
+ | PlaceElem::Subslice { .. }
+ | PlaceElem::Downcast(..) => None,
+ }
+ }
+ };
+
+ () => {
+ fn visit_projection(
+ &mut self,
+ place_ref: PlaceRef<'tcx>,
+ context: PlaceContext,
+ location: Location,
+ ) {
+ self.super_projection(place_ref, 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() {
+ if context.is_use() {
+ // ^ Only change the context if it is a real use, not a "use" in debuginfo.
+ context = if context.is_mutating_use() {
+ PlaceContext::MutatingUse(MutatingUseContext::Projection)
+ } else {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
+ };
+ }
+ }
+
+ self.visit_local(place.local, context, location);
+
+ self.visit_projection(place.as_ref(), context, location);
+ }
+
+ fn super_projection(
+ &mut self,
+ place_ref: PlaceRef<'tcx>,
+ context: PlaceContext,
+ location: Location,
+ ) {
+ for (base, elem) in place_ref.iter_projections().rev() {
+ let base_proj = base.projection;
+ self.visit_projection_elem(place_ref.local, base_proj, 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:
+ /// ```ignore (illustrative)
+ /// z = x.y;
+ /// f(&x.y);
+ /// ```
+ Projection,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum MutatingUseContext {
+ /// Appears as LHS of an assignment.
+ Store,
+ /// Appears on `SetDiscriminant`
+ SetDiscriminant,
+ /// Appears on `Deinit`
+ Deinit,
+ /// Output operand of an inline assembly block.
+ AsmOutput,
+ /// Destination of a call.
+ Call,
+ /// Destination of a yield.
+ Yield,
+ /// 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:
+ /// ```ignore (illustrative)
+ /// 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 a 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.
+ #[inline]
+ pub fn is_drop(&self) -> bool {
+ matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
+ }
+
+ /// Returns `true` if this place context represents a borrow.
+ pub fn is_borrow(&self) -> bool {
+ matches!(
+ self,
+ PlaceContext::NonMutatingUse(
+ NonMutatingUseContext::SharedBorrow
+ | NonMutatingUseContext::ShallowBorrow
+ | NonMutatingUseContext::UniqueBorrow
+ ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+ )
+ }
+
+ /// Returns `true` if this place context represents a storage live or storage dead marker.
+ #[inline]
+ pub fn is_storage_marker(&self) -> bool {
+ matches!(
+ self,
+ PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
+ )
+ }
+
+ /// Returns `true` if this place context represents a use that potentially changes the value.
+ #[inline]
+ pub fn is_mutating_use(&self) -> bool {
+ matches!(self, PlaceContext::MutatingUse(..))
+ }
+
+ /// Returns `true` if this place context represents a use.
+ #[inline]
+ pub fn is_use(&self) -> bool {
+ !matches!(self, PlaceContext::NonUse(..))
+ }
+
+ /// Returns `true` if this place context represents an assignment statement.
+ pub fn is_place_assignment(&self) -> bool {
+ matches!(
+ self,
+ PlaceContext::MutatingUse(
+ MutatingUseContext::Store
+ | MutatingUseContext::Call
+ | MutatingUseContext::AsmOutput,
+ )
+ )
+ }
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
new file mode 100644
index 000000000..d8483e7e4
--- /dev/null
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -0,0 +1,2060 @@
+//! Defines the various compiler queries.
+//!
+//! For more information on the query system, see
+//! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html).
+//! This chapter includes instructions for adding new queries.
+
+// 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! {
+ query trigger_delay_span_bug(key: DefId) -> () {
+ desc { "trigger a delay span bug" }
+ }
+
+ query resolutions(_: ()) -> &'tcx ty::ResolverOutputs {
+ eval_always
+ no_hash
+ desc { "get the resolver outputs" }
+ }
+
+ query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
+ eval_always
+ no_hash
+ desc { "get the resolver for lowering" }
+ }
+
+ /// Return the span for a definition.
+ /// Contrary to `def_span` below, this query returns the full absolute span of the definition.
+ /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
+ /// of rustc_middle::hir::source_map.
+ query source_span(key: LocalDefId) -> Span {
+ desc { "get the source span" }
+ }
+
+ /// 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: ()) -> Crate<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "get the crate HIR" }
+ }
+
+ /// All items in the crate.
+ query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "get HIR crate items" }
+ }
+
+ /// The items in a module.
+ ///
+ /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
+ /// Avoid calling this query directly.
+ query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+
+ /// Gives access to the HIR node for the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
+ desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Gives access to the HIR ID for the given `LocalDefId` owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
+ desc { |tcx| "HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Gives access to the HIR node's parent for the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_owner_parent(key: LocalDefId) -> hir::HirId {
+ desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_owner_nodes(key: LocalDefId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
+ desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Gives access to the HIR attributes inside the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> {
+ desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
+ /// const argument and returns `None` otherwise.
+ ///
+ /// ```ignore (incomplete)
+ /// let a = foo::<7>();
+ /// // ^ Calling `opt_const_param_of` for this argument,
+ ///
+ /// fn foo<const N: usize>()
+ /// // ^ returns this `DefId`.
+ ///
+ /// fn bar() {
+ /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
+ /// }
+ /// ```
+ // It looks like caching this query on disk actually slightly
+ // worsened performance in #74376.
+ //
+ // Once const generics are more prevalently used, we might want to
+ // consider only caching calls returning `Some`.
+ query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
+ desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Given the def_id of a const-generic parameter, computes the associated default const
+ /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
+ query const_param_default(param: DefId) -> ty::Const<'tcx> {
+ desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
+ cache_on_disk_if { param.is_local() }
+ separate_provide_extern
+ }
+
+ /// Returns the [`Ty`][rustc_middle::ty::Ty] of the given [`DefId`]. If the [`DefId`] points
+ /// to an alias, it will "skip" this alias to return the aliased type.
+ ///
+ /// [`DefId`]: rustc_hir::def_id::DefId
+ query type_of(key: DefId) -> Ty<'tcx> {
+ desc { |tcx|
+ "{action} `{path}`",
+ action = {
+ use rustc_hir::def::DefKind;
+ match tcx.def_kind(key) {
+ DefKind::TyAlias => "expanding type alias",
+ DefKind::TraitAlias => "expanding trait alias",
+ _ => "computing type of",
+ }
+ },
+ path = tcx.def_path_str(key),
+ }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ query analysis(key: ()) -> Result<(), ErrorGuaranteed> {
+ eval_always
+ desc { "running analysis passes on this crate" }
+ }
+
+ /// This query checks the fulfillment of collected lint expectations.
+ /// All lint emitting queries have to be done before this is executed
+ /// to ensure that all expectations can be fulfilled.
+ ///
+ /// This is an extra query to enable other drivers (like rustdoc) to
+ /// only execute a small subset of the `analysis` query, while allowing
+ /// lints to be expected. In rustc, this query will be executed as part of
+ /// the `analysis` query and doesn't have to be called a second time.
+ ///
+ /// Tools can additionally pass in a tool filter. That will restrict the
+ /// expectations to only trigger for lints starting with the listed tool
+ /// name. This is useful for cases were not all linting code from rustc
+ /// was called. With the default `None` all registered lints will also
+ /// be checked for expectation fulfillment.
+ query check_expectations(key: Option<Symbol>) -> () {
+ eval_always
+ desc { "checking lint expectations (RFC 2383)" }
+ }
+
+ /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
+ /// associated generics.
+ query generics_of(key: DefId) -> ty::Generics {
+ desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// 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> {
+ desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+
+ /// Returns the list of bounds that can be used for
+ /// `SelectionCandidate::ProjectionCandidate(_)` and
+ /// `ProjectionTyCandidate::TraitDef`.
+ /// Specifically this is the bounds written on the trait's type
+ /// definition, or those after the `impl` keyword
+ ///
+ /// ```ignore (incomplete)
+ /// type X: Bound + 'lt
+ /// // ^^^^^^^^^^^
+ /// impl Debug + Display
+ /// // ^^^^^^^^^^^^^^^
+ /// ```
+ ///
+ /// `key` is the `DefId` of the associated type or opaque type.
+ ///
+ /// Bounds from the parent (e.g. with nested impl trait) are not included.
+ query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+ desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Elaborated version of the predicates from `explicit_item_bounds`.
+ ///
+ /// For example:
+ ///
+ /// ```
+ /// trait MyTrait {
+ /// type MyAType: Eq + ?Sized;
+ /// }
+ /// ```
+ ///
+ /// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`,
+ /// and `item_bounds` returns
+ /// ```text
+ /// [
+ /// <Self as Trait>::MyAType: Eq,
+ /// <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType>
+ /// ]
+ /// ```
+ ///
+ /// Bounds from the parent (e.g. with nested impl trait) are not included.
+ query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+ desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
+ }
+
+ query native_libraries(_: CrateNum) -> Vec<NativeLib> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "looking up the native libraries of a linked crate" }
+ separate_provide_extern
+ }
+
+ query lint_levels(_: ()) -> LintLevelMap {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "computing the lint levels for items in this crate" }
+ }
+
+ query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
+ eval_always
+ desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+ desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
+
+ query is_panic_runtime(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate is_panic_runtime" }
+ separate_provide_extern
+ }
+
+ /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
+ query thir_body(key: ty::WithOptConstParam<LocalDefId>)
+ -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed>
+ {
+ // Perf tests revealed that hashing THIR is inefficient (see #85729).
+ no_hash
+ desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
+ /// Create a THIR tree for debugging.
+ query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
+ no_hash
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
+ /// 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(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ 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() }
+ separate_provide_extern
+ }
+ query mir_const_qualif_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> mir::ConstQualifs {
+ desc {
+ |tcx| "const checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
+ }
+ }
+
+ /// Fetch the MIR for a given `DefId` right after it's built - this includes
+ /// unreachable code.
+ query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
+ /// Fetch the MIR for a given `DefId` up till the point where it is
+ /// ready for const qualification.
+ ///
+ /// See the README for the `mir` module for details.
+ query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc {
+ |tcx| "processing MIR for {}`{}`",
+ if key.const_param_did.is_some() { "the const argument " } else { "" },
+ tcx.def_path_str(key.did.to_def_id()),
+ }
+ no_hash
+ }
+
+ /// Try to build an abstract representation of the given constant.
+ query thir_abstract_const(
+ key: DefId
+ ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
+ desc {
+ |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
+ }
+ separate_provide_extern
+ }
+ /// Try to build an abstract representation of the given constant.
+ query thir_abstract_const_of_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
+ desc {
+ |tcx|
+ "building an abstract representation for the const argument {}",
+ tcx.def_path_str(key.0.to_def_id()),
+ }
+ }
+
+ query try_unify_abstract_consts(key:
+ ty::ParamEnvAnd<'tcx, (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>
+ )>) -> bool {
+ desc {
+ |tcx| "trying to unify the generic constants {} and {}",
+ tcx.def_path_str(key.value.0.def.did), tcx.def_path_str(key.value.1.def.did)
+ }
+ }
+
+ query mir_drops_elaborated_and_const_checked(
+ key: ty::WithOptConstParam<LocalDefId>
+ ) -> &'tcx Steal<mir::Body<'tcx>> {
+ no_hash
+ desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
+ query mir_for_ctfe(
+ key: DefId
+ ) -> &'tcx mir::Body<'tcx> {
+ desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
+ desc {
+ |tcx| "MIR for CTFE of the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
+ }
+ }
+
+ query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
+ (
+ &'tcx Steal<mir::Body<'tcx>>,
+ &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
+ ) {
+ no_hash
+ desc {
+ |tcx| "processing {}`{}`",
+ if key.const_param_did.is_some() { "the const argument " } else { "" },
+ tcx.def_path_str(key.did.to_def_id()),
+ }
+ }
+
+ query symbols_for_closure_captures(
+ key: (LocalDefId, LocalDefId)
+ ) -> Vec<rustc_span::Symbol> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc {
+ |tcx| "symbols for captures of closure `{}` in `{}`",
+ tcx.def_path_str(key.1.to_def_id()),
+ tcx.def_path_str(key.0.to_def_id())
+ }
+ }
+
+ /// 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::Body<'tcx> {
+ desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
+ /// MIR pass (assuming the -Cinstrument-coverage option is enabled).
+ query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
+ desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
+ storage(ArenaCacheSelector<'tcx>)
+ }
+
+ /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
+ /// function was optimized out before codegen, and before being added to the Coverage Map.
+ query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
+ desc {
+ |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`",
+ tcx.def_path_str(key)
+ }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ }
+
+ /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own
+ /// `DefId`. This function returns all promoteds in the specified body. The body references
+ /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because
+ /// after inlining a body may refer to promoteds from other bodies. In that case you still
+ /// need to use the `DefId` of the original body.
+ query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
+ desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+ query promoted_mir_of_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
+ desc {
+ |tcx| "optimizing promoted MIR for the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id()),
+ }
+ }
+
+ /// 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
+ desc { "erasing regions from `{:?}`", ty }
+ }
+
+ query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "wasm import module map" }
+ }
+
+ /// 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(key: DefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns everything that looks like a predicate written explicitly
+ /// by the user on a trait item.
+ ///
+ /// Traits are unusual, because predicates on associated types are
+ /// converted into bounds on that type for backwards compatibility:
+ ///
+ /// trait X where Self::U: Copy { type U; }
+ ///
+ /// becomes
+ ///
+ /// trait X { type U: Copy; }
+ ///
+ /// `explicit_predicates_of` and `explicit_item_bounds` will then take
+ /// the appropriate subsets of the predicates here.
+ query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Returns the predicates written explicitly by the user.
+ query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Returns the inferred outlives predicates (e.g., for `struct
+ /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
+ query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+ desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// 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 super predicates of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
+ /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the
+ /// subset of super-predicates that reference traits that define the given associated type.
+ /// This is used to avoid cycles in resolving types like `T::Item`.
+ query super_predicates_that_define_assoc_type(key: (DefId, Option<rustc_span::symbol::Ident>)) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing the super traits of `{}`{}",
+ tcx.def_path_str(key.0),
+ if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() },
+ }
+ }
+
+ /// 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, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
+ }
+
+ query trait_def(key: DefId) -> ty::TraitDef {
+ desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+ query adt_def(key: DefId) -> ty::AdtDef<'tcx> {
+ desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+ query adt_destructor(key: DefId) -> Option<ty::Destructor> {
+ desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ // 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(
+ key: DefId
+ ) -> AdtSizedConstraint<'tcx> {
+ desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
+ cycle_delay_bug
+ }
+
+ query adt_dtorck_constraint(
+ key: DefId
+ ) -> Result<&'tcx DropckConstraint<'tcx>, NoSolution> {
+ desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
+ }
+
+ /// 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. Consider using `is_const_fn` or `is_const_fn_raw` instead.
+ query constness(key: DefId) -> hir::Constness {
+ desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ query asyncness(key: DefId) -> hir::IsAsync {
+ desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// 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(key: DefId) -> bool {
+ desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
+ query is_foreign_item(key: DefId) -> bool {
+ desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
+ query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
+ desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ /// Gets a map with the variance of every item; use `item_variance` instead.
+ query crate_variances(_: ()) -> ty::CrateVariancesMap<'tcx> {
+ storage(ArenaCacheSelector<'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(def_id: DefId) -> &'tcx [ty::Variance] {
+ desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ /// Maps from thee `DefId` of a type to its (inferred) outlives.
+ query inferred_outlives_crate(_: ()) -> ty::CratePredicatesMap<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "computing the inferred outlives predicates for items in this crate" }
+ }
+
+ /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
+ query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
+ desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Maps from a trait item to the trait item "descriptor".
+ query associated_item(key: DefId) -> ty::AssocItem {
+ desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Collects the associated items defined on a trait or impl.
+ query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+ }
+
+ /// Maps from associated items on a trait to the corresponding associated
+ /// item on the impl specified by `impl_id`.
+ ///
+ /// For example, with the following code
+ ///
+ /// ```
+ /// struct Type {}
+ /// // DefId
+ /// trait Trait { // trait_id
+ /// fn f(); // trait_f
+ /// fn g() {} // trait_g
+ /// }
+ ///
+ /// impl Trait for Type { // impl_id
+ /// fn f() {} // impl_f
+ /// fn g() {} // impl_g
+ /// }
+ /// ```
+ ///
+ /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
+ ///`{ trait_f: impl_f, trait_g: impl_g }`
+ query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+ }
+
+ /// Given an `impl_id`, return the trait it implements.
+ /// Return `None` if this is an inherent impl.
+ query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
+ desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+ cache_on_disk_if { impl_id.is_local() }
+ separate_provide_extern
+ }
+ query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
+ desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+ cache_on_disk_if { impl_id.is_local() }
+ separate_provide_extern
+ }
+
+ query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
+ desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) }
+ }
+
+ /// 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(key: DefId) -> &'tcx [DefId] {
+ desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] {
+ desc { |tcx| "collecting all inherent impls for `{:?}`", key }
+ }
+
+ /// The result of unsafety-checking this `LocalDefId`.
+ query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+ query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {
+ desc {
+ |tcx| "unsafety-checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
+ }
+ }
+
+ /// Unsafety-check this `LocalDefId` with THIR unsafeck. This should be
+ /// used with `-Zthir-unsafeck`.
+ query thir_check_unsafety(key: LocalDefId) {
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+ query thir_check_unsafety_for_const_arg(key: (LocalDefId, DefId)) {
+ desc {
+ |tcx| "unsafety-checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
+ }
+ }
+
+ /// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error.
+ ///
+ /// Unsafety checking is executed for each method separately, but we only want
+ /// to emit this error once per derive. As there are some impls with multiple
+ /// methods, we use a query for deduplication.
+ query unsafe_derive_on_repr_packed(key: LocalDefId) -> () {
+ desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Computes the signature of the function.
+ query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
+ desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ /// Performs lint checking for the module.
+ query lint_mod(key: LocalDefId) -> () {
+ desc { |tcx| "linting {}", describe_as_module(key, tcx) }
+ }
+
+ /// Checks the attributes in the module.
+ query check_mod_attrs(key: LocalDefId) -> () {
+ desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Checks for uses of unstable APIs in the module.
+ query check_mod_unstable_api_usage(key: LocalDefId) -> () {
+ 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: LocalDefId) -> () {
+ desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Checks the loops in the module.
+ query check_mod_loops(key: LocalDefId) -> () {
+ desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_naked_functions(key: LocalDefId) -> () {
+ desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_item_types(key: LocalDefId) -> () {
+ desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_privacy(key: LocalDefId) -> () {
+ desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_liveness(key: LocalDefId) -> () {
+ desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Return the live symbols in the crate for dead code check.
+ ///
+ /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
+ /// their respective impl (i.e., part of the derive macro)
+ query live_symbols_and_ignored_derived_traits(_: ()) -> (
+ FxHashSet<LocalDefId>,
+ FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
+ ) {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "find live symbols in crate" }
+ }
+
+ query check_mod_deathness(key: LocalDefId) -> () {
+ desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_impl_wf(key: LocalDefId) -> () {
+ desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_type_wf(key: LocalDefId) -> () {
+ desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) }
+ }
+
+ query collect_mod_item_types(key: LocalDefId) -> () {
+ desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Caches `CoerceUnsized` kinds for impls on custom types.
+ query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
+ desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ query typeck_item_bodies(_: ()) -> () {
+ desc { "type-checking all item bodies" }
+ }
+
+ query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+ query typeck_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> &'tcx ty::TypeckResults<'tcx> {
+ desc {
+ |tcx| "type-checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id()),
+ }
+ }
+ query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ load_cached(tcx, id) {
+ let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+ .on_disk_cache().as_ref()
+ .and_then(|c| c.try_load_query_result(*tcx, id));
+
+ typeck_results.map(|x| &*tcx.arena.alloc(x))
+ }
+ }
+
+ query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
+ desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+
+ query has_typeck_results(def_id: DefId) -> bool {
+ desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
+ }
+
+ query coherent_trait(def_id: DefId) -> () {
+ desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Borrow-checks the function body. If this is a closure, returns
+ /// additional requirements that the closure's creator must verify.
+ query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
+ desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
+ }
+ query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
+ desc {
+ |tcx| "borrow-checking the const argument`{}`",
+ tcx.def_path_str(key.0.to_def_id())
+ }
+ }
+
+ /// Gets a complete map from all types to their inherent impls.
+ /// Not meant to be used directly outside of coherence.
+ query crate_inherent_impls(k: ()) -> CrateInherentImpls {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "all inherent impls defined in crate" }
+ }
+
+ /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
+ /// Not meant to be used directly outside of coherence.
+ query crate_inherent_impls_overlap_check(_: ()) -> () {
+ desc { "check for overlap between inherent impls defined in this crate" }
+ }
+
+ /// Checks whether all impls in the crate pass the overlap check, returning
+ /// which impls fail it. If all impls are correct, the returned slice is empty.
+ query orphan_check_impl(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
+ desc { |tcx|
+ "checking whether impl `{}` follows the orphan rules",
+ tcx.def_path_str(key.to_def_id()),
+ }
+ }
+
+ /// Check whether the function has any recursion that could cause the inliner to trigger
+ /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
+ /// current function, just all intermediate functions.
+ query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool {
+ fatal_cycle
+ desc { |tcx|
+ "computing if `{}` (transitively) calls `{}`",
+ key.0,
+ tcx.def_path_str(key.1.to_def_id()),
+ }
+ }
+
+ /// Obtain all the calls into other local functions
+ query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
+ fatal_cycle
+ desc { |tcx|
+ "computing all local function calls in `{}`",
+ tcx.def_path_str(key.def_id()),
+ }
+ }
+
+ /// Evaluates a constant and returns the computed allocation.
+ ///
+ /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
+ query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+ -> EvalToAllocationRawResult<'tcx> {
+ desc { |tcx|
+ "const-evaluating + checking `{}`",
+ key.value.display(tcx)
+ }
+ cache_on_disk_if { true }
+ }
+
+ /// Evaluates const items or anonymous constants
+ /// (such as enum variant explicit discriminants or array lengths)
+ /// into a representation suitable for the type system and const generics.
+ ///
+ /// **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_global_id`.
+ query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+ -> EvalToConstValueResult<'tcx> {
+ desc { |tcx|
+ "simplifying constant for the type system `{}`",
+ key.value.display(tcx)
+ }
+ cache_on_disk_if { true }
+ }
+
+ /// Evaluate a constant and convert it to a type level constant or
+ /// return `None` if that is not possible.
+ query eval_to_valtree(
+ key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>
+ ) -> EvalToValTreeResult<'tcx> {
+ desc { "evaluating type-level constant" }
+ }
+
+ /// Converts a type level constant value into `ConstValue`
+ query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> ConstValue<'tcx> {
+ desc { "converting type-level constant value to mir constant value"}
+ }
+
+ /// Destructures array, ADT or tuple constants into the constants
+ /// of their fields.
+ query destructure_const(key: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
+ desc { "destructuring type level constant"}
+ }
+
+ /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
+ /// and its field values.
+ query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option<mir::DestructuredMirConstant<'tcx>> {
+ desc { "destructuring mir constant"}
+ remap_env_constness
+ }
+
+ /// Dereference a constant reference or raw pointer and turn the result into a constant
+ /// again.
+ query deref_mir_constant(
+ key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+ ) -> mir::ConstantKind<'tcx> {
+ desc { "dereferencing mir constant" }
+ remap_env_constness
+ }
+
+ query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
+ desc { "get a &core::panic::Location referring to a span" }
+ }
+
+ // FIXME get rid of this with valtrees
+ query lit_to_const(
+ key: LitToConstInput<'tcx>
+ ) -> Result<ty::Const<'tcx>, LitToConstError> {
+ desc { "converting literal to const" }
+ }
+
+ query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result<mir::ConstantKind<'tcx>, LitToConstError> {
+ desc { "converting literal to mir constant" }
+ }
+
+ query check_match(key: DefId) {
+ desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+
+ /// Performs part of the privacy check and computes "access levels".
+ query privacy_access_levels(_: ()) -> &'tcx AccessLevels {
+ eval_always
+ desc { "privacy access levels" }
+ }
+ query check_private_in_public(_: ()) -> () {
+ eval_always
+ desc { "checking for private elements in public interfaces" }
+ }
+
+ query reachable_set(_: ()) -> FxHashSet<LocalDefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ 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(def_id: DefId) -> &'tcx crate::middle::region::ScopeTree {
+ desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Generates a MIR body for the shim.
+ query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ 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<'tcx> {
+ desc { "computing the symbol for `{}`", key }
+ cache_on_disk_if { true }
+ }
+
+ query opt_def_kind(def_id: DefId) -> Option<DefKind> {
+ desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ /// Gets the span for the definition.
+ query def_span(def_id: DefId) -> Span {
+ desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ /// Gets the span for the identifier of the definition.
+ query def_ident_span(def_id: DefId) -> Option<Span> {
+ desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ query lookup_stability(def_id: DefId) -> Option<attr::Stability> {
+ desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ query lookup_const_stability(def_id: DefId) -> Option<attr::ConstStability> {
+ desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ query should_inherit_track_caller(def_id: DefId) -> bool {
+ desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
+ desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ /// Determines whether an item is annotated with `doc(hidden)`.
+ query is_doc_hidden(def_id: DefId) -> bool {
+ desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
+ }
+
+ /// Returns the attributes on the item at `def_id`.
+ ///
+ /// Do not use this directly, use `tcx.get_attrs` instead.
+ query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
+ desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
+ }
+
+ query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
+ desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
+ desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
+ desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+ /// Gets the rendered value of the specified constant or associated constant.
+ /// Used by rustdoc.
+ query rendered_const(def_id: DefId) -> String {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+ query impl_parent(def_id: DefId) -> Option<DefId> {
+ desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ query is_ctfe_mir_available(key: DefId) -> bool {
+ desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+ query is_mir_available(key: DefId) -> bool {
+ desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ separate_provide_extern
+ }
+
+ query own_existential_vtable_entries(
+ key: ty::PolyExistentialTraitRef<'tcx>
+ ) -> &'tcx [DefId] {
+ desc { |tcx| "finding all existential vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+ }
+
+ query vtable_entries(key: ty::PolyTraitRef<'tcx>)
+ -> &'tcx [ty::VtblEntry<'tcx>] {
+ desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+ }
+
+ query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
+ desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+ key.1, key.0 }
+ }
+
+ query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
+ desc { |tcx| "vtable const allocation for <{} as {}>",
+ key.0,
+ key.1.map(|trait_ref| format!("{}", trait_ref)).unwrap_or("_".to_owned())
+ }
+ }
+
+ query codegen_fulfill_obligation(
+ key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
+ ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
+ cache_on_disk_if { true }
+ desc { |tcx|
+ "checking if `{}` fulfills its obligations",
+ tcx.def_path_str(key.1.def_id())
+ }
+ }
+
+ /// Return all `impl` blocks in the current crate.
+ query all_local_trait_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap<DefId, Vec<LocalDefId>> {
+ desc { "local trait impls" }
+ }
+
+ /// Given a trait `trait_id`, return all known `impl` blocks.
+ query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
+ }
+
+ query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
+ cache_on_disk_if { true }
+ }
+ query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
+ desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
+ }
+
+ /// Gets the ParameterEnvironment for a given item; this environment
+ /// will be in "user-facing" mode, meaning that it is suitable 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(def_id: DefId) -> ty::ParamEnv<'tcx> {
+ desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Like `param_env`, but returns the `ParamEnv` in `Reveal::All` mode.
+ /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
+ /// as this method is more efficient.
+ query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
+ desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// 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 {
+ desc { "computing whether `{}` is `Copy`", env.value }
+ remap_env_constness
+ }
+ /// Query backing `Ty::is_sized`.
+ query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` is `Sized`", env.value }
+ remap_env_constness
+ }
+ /// Query backing `Ty::is_freeze`.
+ query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` is freeze", env.value }
+ remap_env_constness
+ }
+ /// Query backing `Ty::is_unpin`.
+ query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` is `Unpin`", env.value }
+ remap_env_constness
+ }
+ /// Query backing `Ty::needs_drop`.
+ query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` needs drop", env.value }
+ remap_env_constness
+ }
+ /// Query backing `Ty::has_significant_drop_raw`.
+ query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` has a significant drop", env.value }
+ remap_env_constness
+ }
+
+ /// Query backing `Ty::is_structural_eq_shallow`.
+ ///
+ /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
+ /// correctly.
+ query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
+ desc {
+ "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
+ ty
+ }
+ }
+
+ /// 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(def_id: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+ desc { |tcx| "computing when `{}` needs drop", tcx.def_path_str(def_id) }
+ cache_on_disk_if { true }
+ }
+
+ /// A list of types where the ADT requires drop if and only if any of those types
+ /// has significant drop. A type marked with the attribute `rustc_insignificant_dtor`
+ /// is considered to not be significant. A drop is significant if it is implemented
+ /// by the user or does anything that will have any observable behavior (other than
+ /// freeing up memory). If the ADT is known to have a significant destructor then
+ /// `Err(AlwaysRequiresDrop)` is returned.
+ query adt_significant_drop_tys(def_id: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+ desc { |tcx| "computing when `{}` has a significant destructor", tcx.def_path_str(def_id) }
+ cache_on_disk_if { false }
+ }
+
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode, and will normalize the input type.
+ query layout_of(
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+ ) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
+ desc { "computing layout of `{}`", key.value }
+ remap_env_constness
+ }
+
+ /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+ ///
+ /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+ /// instead, where the instance is an `InstanceDef::Virtual`.
+ query fn_abi_of_fn_ptr(
+ key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+ ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+ desc { "computing call ABI of `{}` function pointers", key.value.0 }
+ remap_env_constness
+ }
+
+ /// 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 an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+ query fn_abi_of_instance(
+ key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+ ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+ desc { "computing call ABI of `{}`", key.value.0 }
+ remap_env_constness
+ }
+
+ query dylib_dependency_formats(_: CrateNum)
+ -> &'tcx [(CrateNum, LinkagePreference)] {
+ desc { "dylib dependency formats of crate" }
+ separate_provide_extern
+ }
+
+ query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "get the linkage format of all dependencies" }
+ }
+
+ query is_compiler_builtins(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate is_compiler_builtins" }
+ separate_provide_extern
+ }
+ query has_global_allocator(_: CrateNum) -> bool {
+ // This query depends on untracked global state in CStore
+ eval_always
+ fatal_cycle
+ desc { "checking if the crate has_global_allocator" }
+ separate_provide_extern
+ }
+ query has_panic_handler(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate has_panic_handler" }
+ separate_provide_extern
+ }
+ query is_profiler_runtime(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "query a crate is `#![profiler_runtime]`" }
+ separate_provide_extern
+ }
+ query has_ffi_unwind_calls(key: LocalDefId) -> bool {
+ desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+ query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
+ fatal_cycle
+ desc { "query a crate's required panic strategy" }
+ separate_provide_extern
+ }
+ query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
+ fatal_cycle
+ desc { "query a crate's configured panic-in-drop strategy" }
+ separate_provide_extern
+ }
+ query is_no_builtins(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "test whether a crate has `#![no_builtins]`" }
+ separate_provide_extern
+ }
+ query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
+ fatal_cycle
+ desc { "query a crate's symbol mangling version" }
+ separate_provide_extern
+ }
+
+ query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
+ eval_always
+ desc { "getting crate's ExternCrateData" }
+ separate_provide_extern
+ }
+
+ query specializes(_: (DefId, DefId)) -> bool {
+ desc { "computing whether impls specialize one another" }
+ }
+ query in_scope_traits_map(_: LocalDefId)
+ -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
+ desc { "traits in scope at a block" }
+ }
+
+ query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
+ desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ }
+
+ query impl_defaultness(def_id: DefId) -> hir::Defaultness {
+ desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+
+ query check_well_formed(key: LocalDefId) -> () {
+ desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ // 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)
+ -> DefIdMap<SymbolExportInfo> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "looking up the exported symbols of a crate" }
+ separate_provide_extern
+ }
+ query is_reachable_non_generic(def_id: DefId) -> bool {
+ desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
+ }
+ query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
+ desc { |tcx|
+ "checking whether `{}` is reachable from outside the crate",
+ tcx.def_path_str(def_id.to_def_id()),
+ }
+ }
+
+ /// 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(_: ()) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "collecting available upstream monomorphizations" }
+ }
+
+ /// 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(def_id: DefId)
+ -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
+ {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx|
+ "collecting available upstream monomorphizations for `{}`",
+ tcx.def_path_str(def_id),
+ }
+ separate_provide_extern
+ }
+
+ /// 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 }
+ }
+
+ query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "looking up the foreign modules of a linked crate" }
+ separate_provide_extern
+ }
+
+ /// 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(_: ()) -> Option<(DefId, EntryFnType)> {
+ desc { "looking up the entry function of a crate" }
+ }
+ query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
+ desc { "looking up the derive registrar for a crate" }
+ }
+ // The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
+ // Changing the name should cause a compiler error, but in case that changes, be aware.
+ query crate_hash(_: CrateNum) -> Svh {
+ eval_always
+ desc { "looking up the hash a crate" }
+ separate_provide_extern
+ }
+ query crate_host_hash(_: CrateNum) -> Option<Svh> {
+ eval_always
+ desc { "looking up the hash of a host version of a crate" }
+ separate_provide_extern
+ }
+ query extra_filename(_: CrateNum) -> String {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "looking up the extra filename for a crate" }
+ separate_provide_extern
+ }
+ query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "looking up the paths for extern crates" }
+ separate_provide_extern
+ }
+
+ /// Given a crate and a trait, look up all impls of that trait in the crate.
+ /// Return `(impl_id, self_ty)`.
+ query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option<SimplifiedType>)] {
+ desc { "looking up implementations of a trait in a crate" }
+ separate_provide_extern
+ }
+
+ /// Collects all incoherent impls for the given crate and type.
+ ///
+ /// Do not call this directly, but instead use the `incoherent_impls` query.
+ /// This query is only used to get the data necessary for that query.
+ query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] {
+ desc { |tcx| "collecting all impls for a type in a crate" }
+ separate_provide_extern
+ }
+
+ query is_dllimport_foreign_item(def_id: DefId) -> bool {
+ desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
+ }
+ query is_statically_included_foreign_item(def_id: DefId) -> bool {
+ desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) }
+ }
+ query native_library_kind(def_id: DefId)
+ -> Option<NativeLibKind> {
+ desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
+ }
+
+ /// Does lifetime resolution, but does not descend into trait items. This
+ /// should only be used for resolving lifetimes of on trait definitions,
+ /// and is used to avoid cycles. Importantly, `resolve_lifetimes` still visits
+ /// the same lifetimes and is responsible for diagnostics.
+ /// See `rustc_resolve::late::lifetimes for details.
+ query resolve_lifetimes_trait_definition(_: LocalDefId) -> ResolveLifetimes {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "resolving lifetimes for a trait definition" }
+ }
+ /// Does lifetime resolution on items. Importantly, we can't resolve
+ /// lifetimes directly on things like trait methods, because of trait params.
+ /// See `rustc_resolve::late::lifetimes for details.
+ query resolve_lifetimes(_: LocalDefId) -> ResolveLifetimes {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "resolving lifetimes" }
+ }
+ query named_region_map(_: LocalDefId) ->
+ Option<&'tcx FxHashMap<ItemLocalId, Region>> {
+ desc { "looking up a named region" }
+ }
+ query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> {
+ desc { "testing if a region is late bound" }
+ }
+ /// For a given item (like a struct), gets the default lifetimes to be used
+ /// for each parameter if a trait object were to be passed for that parameter.
+ /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`.
+ /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
+ query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> {
+ desc { "looking up lifetime defaults for a region on an item" }
+ }
+ query late_bound_vars_map(_: LocalDefId)
+ -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
+ desc { "looking up late bound vars" }
+ }
+
+ query visibility(def_id: DefId) -> ty::Visibility {
+ desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
+ }
+
+ /// Computes the set of modules from which this type is visibly uninhabited.
+ /// To check whether a type is uninhabited at all (not just from a given module), you could
+ /// check whether the forest is empty.
+ query type_uninhabited_from(
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+ ) -> ty::inhabitedness::DefIdForest<'tcx> {
+ desc { "computing the inhabitedness of `{:?}`", key }
+ remap_env_constness
+ }
+
+ query dep_kind(_: CrateNum) -> CrateDepKind {
+ eval_always
+ desc { "fetching what a dependency looks like" }
+ separate_provide_extern
+ }
+
+ /// Gets the name of the crate.
+ query crate_name(_: CrateNum) -> Symbol {
+ eval_always
+ desc { "fetching what a crate is named" }
+ separate_provide_extern
+ }
+ query module_children(def_id: DefId) -> &'tcx [ModChild] {
+ desc { |tcx| "collecting child items of module `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
+ }
+ query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
+ desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ }
+
+ query lib_features(_: ()) -> LibFeatures {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the lib features map" }
+ }
+ query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option<Symbol>)] {
+ desc { "calculating the lib features defined in a crate" }
+ separate_provide_extern
+ }
+ query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the implications between `#[unstable]` features defined in a crate" }
+ separate_provide_extern
+ }
+ /// Whether the function is an intrinsic
+ query is_intrinsic(def_id: DefId) -> bool {
+ desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
+ separate_provide_extern
+ }
+ /// Returns the lang items defined in another crate by loading it from metadata.
+ query get_lang_items(_: ()) -> LanguageItems {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "calculating the lang items map" }
+ }
+
+ /// Returns all diagnostic items defined in all crates.
+ query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
+ storage(ArenaCacheSelector<'tcx>)
+ 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" }
+ separate_provide_extern
+ }
+
+ /// Returns the diagnostic items defined in a crate.
+ query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the diagnostic items map in a crate" }
+ separate_provide_extern
+ }
+
+ query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
+ desc { "calculating the missing lang items in a crate" }
+ separate_provide_extern
+ }
+ query visible_parent_map(_: ()) -> DefIdMap<DefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the visible parent map" }
+ }
+ query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating trimmed def paths" }
+ }
+ query missing_extern_crate_item(_: CrateNum) -> bool {
+ eval_always
+ desc { "seeing if we're missing an `extern crate` item for this crate" }
+ separate_provide_extern
+ }
+ query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "looking at the source for a crate" }
+ separate_provide_extern
+ }
+ /// Returns the debugger visualizers defined for this crate.
+ query debugger_visualizers(_: CrateNum) -> Vec<rustc_span::DebuggerVisualizerFile> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "looking up the debugger visualizers for this crate" }
+ separate_provide_extern
+ }
+ query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
+ eval_always
+ desc { "generating a postorder list of CrateNums" }
+ }
+ /// Returns whether or not the crate with CrateNum 'cnum'
+ /// is marked as a private dependency
+ query is_private_dep(c: CrateNum) -> bool {
+ eval_always
+ desc { "check whether crate {} is a private dependency", c }
+ separate_provide_extern
+ }
+ query allocator_kind(_: ()) -> Option<AllocatorKind> {
+ eval_always
+ desc { "allocator kind for the current crate" }
+ }
+
+ query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
+ desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
+ }
+ query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
+ desc { "fetching potentially unused trait imports" }
+ }
+ query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] {
+ desc { "looking up all possibly unused extern crates" }
+ }
+ query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
+ desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ }
+
+ query stability_index(_: ()) -> stability::Index {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "calculating the stability index for the local crate" }
+ }
+ query crates(_: ()) -> &'tcx [CrateNum] {
+ eval_always
+ desc { "fetching all foreign CrateNum instances" }
+ }
+
+ /// A list of all traits in a crate, used by rustdoc and error reporting.
+ /// NOTE: Not named just `traits` due to a naming conflict.
+ query traits_in_crate(_: CrateNum) -> &'tcx [DefId] {
+ desc { "fetching all traits in a crate" }
+ separate_provide_extern
+ }
+
+ /// 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(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
+ desc { "exported_symbols" }
+ cache_on_disk_if { *cnum == LOCAL_CRATE }
+ separate_provide_extern
+ }
+
+ query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
+ eval_always
+ desc { "collect_and_partition_mono_items" }
+ }
+ query is_codegened_item(def_id: DefId) -> bool {
+ desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
+ }
+
+ /// All items participating in code generation together with items inlined into them.
+ query codegened_and_inlined_items(_: ()) -> &'tcx DefIdSet {
+ eval_always
+ desc { "codegened_and_inlined_items" }
+ }
+
+ query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
+ desc { "codegen_unit" }
+ }
+ query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
+ cache_on_disk_if { key.def_id().is_local() }
+ desc {
+ |tcx| "determining which generic parameters are unused by `{}`",
+ tcx.def_path_str(key.def_id())
+ }
+ separate_provide_extern
+ }
+ query backend_optimization_level(_: ()) -> OptLevel {
+ desc { "optimization level used by backend" }
+ }
+
+ /// Return the filenames where output artefacts shall be stored.
+ ///
+ /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
+ /// has been destroyed.
+ query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
+ eval_always
+ desc { "output_filenames" }
+ }
+
+ /// 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,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_generic_arg_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+ ) -> Result<GenericArg<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ remap_env_constness
+ }
+
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_mir_const_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+ ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ remap_env_constness
+ }
+
+ query implied_outlives_bounds(
+ goal: CanonicalTyGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
+ NoSolution,
+ > {
+ desc { "computing implied outlives bounds for `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// Do not call this query directly:
+ /// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
+ query dropck_outlives(
+ goal: CanonicalTyGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "computing dropck types for `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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> {
+ desc { "evaluating trait selection obligation `{}`", goal.value.value }
+ }
+
+ query evaluate_goal(
+ goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
+ NoSolution
+ > {
+ desc { "evaluating trait selection obligation `{}`", goal.value }
+ }
+
+ /// 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,
+ > {
+ desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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,
+ > {
+ desc { "evaluating `type_op_eq` `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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,
+ > {
+ desc { "evaluating `type_op_subtype` `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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,
+ > {
+ 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,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ remap_env_constness
+ }
+
+ /// 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,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ remap_env_constness
+ }
+
+ query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
+ desc { |tcx|
+ "impossible substituted predicates:`{}`",
+ tcx.def_path_str(key.0)
+ }
+ }
+
+ query method_autoderef_steps(
+ goal: CanonicalTyGoal<'tcx>
+ ) -> MethodAutoderefStepsResult<'tcx> {
+ desc { "computing autoderef types for `{:?}`", goal }
+ remap_env_constness
+ }
+
+ query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "looking up supported 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 {
+ desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
+ }
+
+ query features_query(_: ()) -> &'tcx rustc_feature::Features {
+ eval_always
+ desc { "looking up enabled feature gates" }
+ }
+
+ /// Attempt to resolve the given `DefId` to an `Instance`, for the
+ /// given generics args (`SubstsRef`), returning one of:
+ /// * `Ok(Some(instance))` on success
+ /// * `Ok(None)` when the `SubstsRef` are still too generic,
+ /// and therefore don't allow finding the final `Instance`
+ /// * `Err(ErrorGuaranteed)` when the `Instance` resolution process
+ /// couldn't complete due to errors elsewhere - this is distinct
+ /// from `Ok(None)` to avoid misleading diagnostics when an error
+ /// has already been/will be emitted, for the original cause
+ query resolve_instance(
+ key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
+ ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
+ desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
+ remap_env_constness
+ }
+
+ query resolve_instance_of_const_arg(
+ key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>
+ ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
+ desc {
+ "resolving instance of the const argument `{}`",
+ ty::Instance::new(key.value.0.to_def_id(), key.value.2),
+ }
+ remap_env_constness
+ }
+
+ query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+ desc { "normalizing opaque types in {:?}", key }
+ }
+
+ /// 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.)
+ query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "conservatively checking if {:?} is privately uninhabited", key }
+ remap_env_constness
+ }
+
+ query limits(key: ()) -> Limits {
+ desc { "looking up limits" }
+ }
+
+ /// Performs an HIR-based well-formed check on the item with the given `HirId`. If
+ /// we get an `Unimplemented` error that matches the provided `Predicate`, return
+ /// the cause of the newly created obligation.
+ ///
+ /// This is only used by error-reporting code to get a better cause (in particular, a better
+ /// span) for an *existing* error. Therefore, it is best-effort, and may never handle
+ /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
+ /// because the `ty::Ty`-based wfcheck is always run.
+ query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ no_hash
+ desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
+ }
+
+
+ /// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
+ /// `--target` and similar).
+ query global_backend_features(_: ()) -> Vec<String> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "computing the backend features for CLI flags" }
+ }
+
+ query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
+
+ query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool {
+ desc { "checking to see if {:?} permits being left uninit", key.ty }
+ }
+
+ query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
+ desc { "checking to see if {:?} permits being left zeroed", key.ty }
+ }
+}
diff --git a/compiler/rustc_middle/src/tests.rs b/compiler/rustc_middle/src/tests.rs
new file mode 100644
index 000000000..757e0bd3b
--- /dev/null
+++ b/compiler/rustc_middle/src/tests.rs
@@ -0,0 +1,13 @@
+use super::*;
+
+// FIXME(#27438): right now the unit tests of librustc_middle 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/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
new file mode 100644
index 000000000..b856af1d8
--- /dev/null
+++ b/compiler/rustc_middle/src/thir.rs
@@ -0,0 +1,821 @@
+//! THIR datatypes and definitions. See the [rustc dev guide] for more info.
+//!
+//! If you compare the THIR [`ExprKind`] to [`hir::ExprKind`], you will see it is
+//! a good bit simpler. In fact, a number of the more straight-forward
+//! MIR simplifications are already done in the lowering to THIR. For
+//! example, method calls and overloaded operators are absent: they are
+//! expected to be converted into [`ExprKind::Call`] instances.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
+
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::RangeEnd;
+use rustc_index::newtype_index;
+use rustc_index::vec::IndexVec;
+use rustc_middle::infer::canonical::Canonical;
+use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
+use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
+use rustc_middle::ty::adjustment::PointerCast;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
+use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
+use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_target::abi::VariantIdx;
+use rustc_target::asm::InlineAsmRegOrRegClass;
+
+use rustc_span::def_id::LocalDefId;
+use std::fmt;
+use std::ops::Index;
+
+pub mod visit;
+
+newtype_index! {
+ /// An index to an [`Arm`] stored in [`Thir::arms`]
+ #[derive(HashStable)]
+ pub struct ArmId {
+ DEBUG_FORMAT = "a{}"
+ }
+}
+
+newtype_index! {
+ /// An index to an [`Expr`] stored in [`Thir::exprs`]
+ #[derive(HashStable)]
+ pub struct ExprId {
+ DEBUG_FORMAT = "e{}"
+ }
+}
+
+newtype_index! {
+ #[derive(HashStable)]
+ /// An index to a [`Stmt`] stored in [`Thir::stmts`]
+ pub struct StmtId {
+ DEBUG_FORMAT = "s{}"
+ }
+}
+
+macro_rules! thir_with_elements {
+ ($($name:ident: $id:ty => $value:ty,)*) => {
+ /// A container for a THIR body.
+ ///
+ /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
+ #[derive(Debug, HashStable, Clone)]
+ pub struct Thir<'tcx> {
+ $(
+ pub $name: IndexVec<$id, $value>,
+ )*
+ }
+
+ impl<'tcx> Thir<'tcx> {
+ pub fn new() -> Thir<'tcx> {
+ Thir {
+ $(
+ $name: IndexVec::new(),
+ )*
+ }
+ }
+ }
+
+ $(
+ impl<'tcx> Index<$id> for Thir<'tcx> {
+ type Output = $value;
+ fn index(&self, index: $id) -> &Self::Output {
+ &self.$name[index]
+ }
+ }
+ )*
+ }
+}
+
+thir_with_elements! {
+ arms: ArmId => Arm<'tcx>,
+ exprs: ExprId => Expr<'tcx>,
+ stmts: StmtId => Stmt<'tcx>,
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum LintLevel {
+ Inherited,
+ Explicit(hir::HirId),
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct Block {
+ /// Whether the block itself has a label. Used by `label: {}`
+ /// and `try` blocks.
+ ///
+ /// This does *not* include labels on loops, e.g. `'label: loop {}`.
+ pub targeted_by_break: bool,
+ pub region_scope: region::Scope,
+ pub opt_destruction_scope: Option<region::Scope>,
+ /// The span of the block, including the opening braces,
+ /// the label, and the `unsafe` keyword, if present.
+ pub span: Span,
+ /// The statements in the blocK.
+ pub stmts: Box<[StmtId]>,
+ /// The trailing expression of the block, if any.
+ pub expr: Option<ExprId>,
+ pub safety_mode: BlockSafety,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct Adt<'tcx> {
+ /// The ADT we're constructing.
+ pub adt_def: AdtDef<'tcx>,
+ /// The variant of the ADT.
+ pub variant_index: VariantIdx,
+ pub substs: SubstsRef<'tcx>,
+
+ /// Optional user-given substs: for something like `let x =
+ /// Bar::<T> { ... }`.
+ pub user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+
+ pub fields: Box<[FieldExpr]>,
+ /// The base, e.g. `Foo {x: 1, .. base}`.
+ pub base: Option<FruInfo<'tcx>>,
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum BlockSafety {
+ Safe,
+ /// A compiler-generated unsafe block
+ BuiltinUnsafe,
+ /// An `unsafe` block. The `HirId` is the ID of the block.
+ ExplicitUnsafe(hir::HirId),
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct Stmt<'tcx> {
+ pub kind: StmtKind<'tcx>,
+ pub opt_destruction_scope: Option<region::Scope>,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub enum StmtKind<'tcx> {
+ /// An expression with a trailing semicolon.
+ Expr {
+ /// The scope for this statement; may be used as lifetime of temporaries.
+ scope: region::Scope,
+
+ /// The expression being evaluated in this statement.
+ expr: ExprId,
+ },
+
+ /// A `let` binding.
+ Let {
+ /// The scope for variables bound in this `let`; it covers this and
+ /// all the remaining statements in the block.
+ remainder_scope: region::Scope,
+
+ /// The scope for the initialization itself; might be used as
+ /// lifetime of temporaries.
+ init_scope: region::Scope,
+
+ /// `let <PAT> = ...`
+ ///
+ /// If a type annotation is included, it is added as an ascription pattern.
+ pattern: Pat<'tcx>,
+
+ /// `let pat: ty = <INIT>`
+ initializer: Option<ExprId>,
+
+ /// `let pat: ty = <INIT> else { <ELSE> }
+ else_block: Option<Block>,
+
+ /// The lint level for this `let` statement.
+ lint_level: LintLevel,
+ },
+}
+
+#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct LocalVarId(pub hir::HirId);
+
+/// A THIR expression.
+#[derive(Clone, Debug, HashStable)]
+pub struct Expr<'tcx> {
+ /// The type of this expression
+ pub ty: Ty<'tcx>,
+
+ /// The lifetime of this expression if it should be spilled into a
+ /// temporary; should be `None` only if in a constant context
+ pub temp_lifetime: Option<region::Scope>,
+
+ /// span of the expression in the source
+ pub span: Span,
+
+ /// kind of expression
+ pub kind: ExprKind<'tcx>,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub enum ExprKind<'tcx> {
+ /// `Scope`s are used to explicitly mark destruction scopes,
+ /// and to track the `HirId` of the expressions within the scope.
+ Scope {
+ region_scope: region::Scope,
+ lint_level: LintLevel,
+ value: ExprId,
+ },
+ /// A `box <value>` expression.
+ Box {
+ value: ExprId,
+ },
+ /// An `if` expression.
+ If {
+ if_then_scope: region::Scope,
+ cond: ExprId,
+ then: ExprId,
+ else_opt: Option<ExprId>,
+ },
+ /// A function call. Method calls and overloaded operators are converted to plain function calls.
+ Call {
+ /// The type of the function. This is often a [`FnDef`] or a [`FnPtr`].
+ ///
+ /// [`FnDef`]: ty::TyKind::FnDef
+ /// [`FnPtr`]: ty::TyKind::FnPtr
+ ty: Ty<'tcx>,
+ /// The function itself.
+ fun: ExprId,
+ /// The arguments passed to the function.
+ ///
+ /// Note: in some cases (like calling a closure), the function call `f(...args)` gets
+ /// rewritten as a call to a function trait method (e.g. `FnOnce::call_once(f, (...args))`).
+ args: Box<[ExprId]>,
+ /// Whether this is from an overloaded operator rather than a
+ /// function call from HIR. `true` for overloaded function call.
+ from_hir_call: bool,
+ /// The span of the function, without the dot and receiver
+ /// (e.g. `foo(a, b)` in `x.foo(a, b)`).
+ fn_span: Span,
+ },
+ /// A *non-overloaded* dereference.
+ Deref {
+ arg: ExprId,
+ },
+ /// A *non-overloaded* binary operation.
+ Binary {
+ op: BinOp,
+ lhs: ExprId,
+ rhs: ExprId,
+ },
+ /// A logical operation. This is distinct from `BinaryOp` because
+ /// the operands need to be lazily evaluated.
+ LogicalOp {
+ op: LogicalOp,
+ lhs: ExprId,
+ rhs: ExprId,
+ },
+ /// A *non-overloaded* unary operation. Note that here the deref (`*`)
+ /// operator is represented by `ExprKind::Deref`.
+ Unary {
+ op: UnOp,
+ arg: ExprId,
+ },
+ /// A cast: `<source> as <type>`. The type we cast to is the type of
+ /// the parent expression.
+ Cast {
+ source: ExprId,
+ },
+ Use {
+ source: ExprId,
+ }, // Use a lexpr to get a vexpr.
+ /// A coercion from `!` to any type.
+ NeverToAny {
+ source: ExprId,
+ },
+ /// A pointer cast. More information can be found in [`PointerCast`].
+ Pointer {
+ cast: PointerCast,
+ source: ExprId,
+ },
+ /// A `loop` expression.
+ Loop {
+ body: ExprId,
+ },
+ Let {
+ expr: ExprId,
+ pat: Pat<'tcx>,
+ },
+ /// A `match` expression.
+ Match {
+ scrutinee: ExprId,
+ arms: Box<[ArmId]>,
+ },
+ /// A block.
+ Block {
+ body: Block,
+ },
+ /// An assignment: `lhs = rhs`.
+ Assign {
+ lhs: ExprId,
+ rhs: ExprId,
+ },
+ /// A *non-overloaded* operation assignment, e.g. `lhs += rhs`.
+ AssignOp {
+ op: BinOp,
+ lhs: ExprId,
+ rhs: ExprId,
+ },
+ /// Access to a field of a struct, a tuple, an union, or an enum.
+ Field {
+ lhs: ExprId,
+ /// Variant containing the field.
+ variant_index: VariantIdx,
+ /// This can be a named (`.foo`) or unnamed (`.0`) field.
+ name: Field,
+ },
+ /// A *non-overloaded* indexing operation.
+ Index {
+ lhs: ExprId,
+ index: ExprId,
+ },
+ /// A local variable.
+ VarRef {
+ id: LocalVarId,
+ },
+ /// Used to represent upvars mentioned in a closure/generator
+ UpvarRef {
+ /// DefId of the closure/generator
+ closure_def_id: DefId,
+
+ /// HirId of the root variable
+ var_hir_id: LocalVarId,
+ },
+ /// A borrow, e.g. `&arg`.
+ Borrow {
+ borrow_kind: BorrowKind,
+ arg: ExprId,
+ },
+ /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
+ AddressOf {
+ mutability: hir::Mutability,
+ arg: ExprId,
+ },
+ /// A `break` expression.
+ Break {
+ label: region::Scope,
+ value: Option<ExprId>,
+ },
+ /// A `continue` expression.
+ Continue {
+ label: region::Scope,
+ },
+ /// A `return` expression.
+ Return {
+ value: Option<ExprId>,
+ },
+ /// An inline `const` block, e.g. `const {}`.
+ ConstBlock {
+ did: DefId,
+ substs: SubstsRef<'tcx>,
+ },
+ /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
+ Repeat {
+ value: ExprId,
+ count: ty::Const<'tcx>,
+ },
+ /// An array, e.g. `[a, b, c, d]`.
+ Array {
+ fields: Box<[ExprId]>,
+ },
+ /// A tuple, e.g. `(a, b, c, d)`.
+ Tuple {
+ fields: Box<[ExprId]>,
+ },
+ /// An ADT constructor, e.g. `Foo {x: 1, y: 2}`.
+ Adt(Box<Adt<'tcx>>),
+ /// A type ascription on a place.
+ PlaceTypeAscription {
+ source: ExprId,
+ /// Type that the user gave to this expression
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ /// A type ascription on a value, e.g. `42: i32`.
+ ValueTypeAscription {
+ source: ExprId,
+ /// Type that the user gave to this expression
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ /// A closure definition.
+ Closure {
+ closure_id: LocalDefId,
+ substs: UpvarSubsts<'tcx>,
+ upvars: Box<[ExprId]>,
+ movability: Option<hir::Movability>,
+ fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
+ },
+ /// A literal.
+ Literal {
+ lit: &'tcx hir::Lit,
+ neg: bool,
+ },
+ /// For literals that don't correspond to anything in the HIR
+ NonHirLiteral {
+ lit: ty::ScalarInt,
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ /// A literal of a ZST type.
+ ZstLiteral {
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ /// Associated constants and named constants
+ NamedConst {
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ ConstParam {
+ param: ty::ParamConst,
+ def_id: DefId,
+ },
+ // FIXME improve docs for `StaticRef` by distinguishing it from `NamedConst`
+ /// A literal containing the address of a `static`.
+ ///
+ /// This is only distinguished from `Literal` so that we can register some
+ /// info for diagnostics.
+ StaticRef {
+ alloc_id: AllocId,
+ ty: Ty<'tcx>,
+ def_id: DefId,
+ },
+ /// Inline assembly, i.e. `asm!()`.
+ InlineAsm {
+ template: &'tcx [InlineAsmTemplatePiece],
+ operands: Box<[InlineAsmOperand<'tcx>]>,
+ options: InlineAsmOptions,
+ line_spans: &'tcx [Span],
+ },
+ /// An expression taking a reference to a thread local.
+ ThreadLocalRef(DefId),
+ /// A `yield` expression.
+ Yield {
+ value: ExprId,
+ },
+}
+
+/// Represents the association of a field identifier and an expression.
+///
+/// This is used in struct constructors.
+#[derive(Clone, Debug, HashStable)]
+pub struct FieldExpr {
+ pub name: Field,
+ pub expr: ExprId,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct FruInfo<'tcx> {
+ pub base: ExprId,
+ pub field_types: Box<[Ty<'tcx>]>,
+}
+
+/// A `match` arm.
+#[derive(Clone, Debug, HashStable)]
+pub struct Arm<'tcx> {
+ pub pattern: Pat<'tcx>,
+ pub guard: Option<Guard<'tcx>>,
+ pub body: ExprId,
+ pub lint_level: LintLevel,
+ pub scope: region::Scope,
+ pub span: Span,
+}
+
+/// A `match` guard.
+#[derive(Clone, Debug, HashStable)]
+pub enum Guard<'tcx> {
+ If(ExprId),
+ IfLet(Pat<'tcx>, ExprId),
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum LogicalOp {
+ /// The `&&` operator.
+ And,
+ /// The `||` operator.
+ Or,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub enum InlineAsmOperand<'tcx> {
+ In {
+ reg: InlineAsmRegOrRegClass,
+ expr: ExprId,
+ },
+ Out {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ expr: Option<ExprId>,
+ },
+ InOut {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ expr: ExprId,
+ },
+ SplitInOut {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ in_expr: ExprId,
+ out_expr: Option<ExprId>,
+ },
+ Const {
+ value: mir::ConstantKind<'tcx>,
+ span: Span,
+ },
+ SymFn {
+ value: mir::ConstantKind<'tcx>,
+ span: Span,
+ },
+ SymStatic {
+ def_id: DefId,
+ },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub enum BindingMode {
+ ByValue,
+ ByRef(BorrowKind),
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct FieldPat<'tcx> {
+ pub field: Field,
+ pub pattern: Pat<'tcx>,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct Pat<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub span: Span,
+ pub kind: Box<PatKind<'tcx>>,
+}
+
+impl<'tcx> Pat<'tcx> {
+ pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
+ Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+ }
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub struct Ascription<'tcx> {
+ pub annotation: CanonicalUserTypeAnnotation<'tcx>,
+ /// Variance to use when relating the `user_ty` to the **type of the value being
+ /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
+ /// have a type that is some subtype of the ascribed type.
+ ///
+ /// Note that this variance does not apply for any bindings within subpatterns. The type
+ /// assigned to those bindings must be exactly equal to the `user_ty` given here.
+ ///
+ /// The only place where this field is not `Covariant` is when matching constants, where
+ /// we currently use `Contravariant` -- this is because the constant type just needs to
+ /// be "comparable" to the type of the input value. So, for example:
+ ///
+ /// ```text
+ /// match x { "foo" => .. }
+ /// ```
+ ///
+ /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
+ /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
+ /// of the old type-check for now. See #57280 for details.
+ pub variance: ty::Variance,
+}
+
+#[derive(Clone, Debug, HashStable)]
+pub enum PatKind<'tcx> {
+ /// A wildcard pattern: `_`.
+ Wild,
+
+ AscribeUserType {
+ ascription: Ascription<'tcx>,
+ subpattern: Pat<'tcx>,
+ },
+
+ /// `x`, `ref x`, `x @ P`, etc.
+ Binding {
+ mutability: Mutability,
+ name: Symbol,
+ mode: BindingMode,
+ var: LocalVarId,
+ ty: Ty<'tcx>,
+ subpattern: Option<Pat<'tcx>>,
+ /// Is this the leftmost occurrence of the binding, i.e., is `var` the
+ /// `HirId` of this pattern?
+ is_primary: bool,
+ },
+
+ /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
+ /// multiple variants.
+ Variant {
+ adt_def: AdtDef<'tcx>,
+ substs: SubstsRef<'tcx>,
+ variant_index: VariantIdx,
+ subpatterns: Vec<FieldPat<'tcx>>,
+ },
+
+ /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
+ /// a single variant.
+ Leaf {
+ subpatterns: Vec<FieldPat<'tcx>>,
+ },
+
+ /// `box P`, `&P`, `&mut P`, etc.
+ Deref {
+ subpattern: Pat<'tcx>,
+ },
+
+ /// One of the following:
+ /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
+ /// checking will detect if you use the same string twice in different patterns.
+ /// * integer, bool, char or float, which will be handled by exhaustiveness to cover exactly
+ /// its own value, similar to `&str`, but these values are much simpler.
+ /// * Opaque constants, that must not be matched structurally. So anything that does not derive
+ /// `PartialEq` and `Eq`.
+ Constant {
+ value: mir::ConstantKind<'tcx>,
+ },
+
+ Range(PatRange<'tcx>),
+
+ /// Matches against a slice, checking the length and extracting elements.
+ /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
+ /// e.g., `&[ref xs @ ..]`.
+ Slice {
+ prefix: Vec<Pat<'tcx>>,
+ slice: Option<Pat<'tcx>>,
+ suffix: Vec<Pat<'tcx>>,
+ },
+
+ /// Fixed match against an array; irrefutable.
+ Array {
+ prefix: Vec<Pat<'tcx>>,
+ slice: Option<Pat<'tcx>>,
+ suffix: Vec<Pat<'tcx>>,
+ },
+
+ /// An or-pattern, e.g. `p | q`.
+ /// Invariant: `pats.len() >= 2`.
+ Or {
+ pats: Vec<Pat<'tcx>>,
+ },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct PatRange<'tcx> {
+ pub lo: mir::ConstantKind<'tcx>,
+ pub hi: mir::ConstantKind<'tcx>,
+ pub end: RangeEnd,
+}
+
+impl<'tcx> fmt::Display for Pat<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Printing lists is a chore.
+ let mut first = true;
+ let mut start_or_continue = |s| {
+ if first {
+ first = false;
+ ""
+ } else {
+ s
+ }
+ };
+ let mut start_or_comma = || start_or_continue(", ");
+
+ match *self.kind {
+ PatKind::Wild => write!(f, "_"),
+ PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
+ PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
+ let is_mut = match mode {
+ BindingMode::ByValue => mutability == Mutability::Mut,
+ BindingMode::ByRef(bk) => {
+ write!(f, "ref ")?;
+ matches!(bk, BorrowKind::Mut { .. })
+ }
+ };
+ if is_mut {
+ write!(f, "mut ")?;
+ }
+ write!(f, "{}", name)?;
+ if let Some(ref subpattern) = *subpattern {
+ write!(f, " @ {}", subpattern)?;
+ }
+ Ok(())
+ }
+ PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
+ let variant = match *self.kind {
+ PatKind::Variant { adt_def, variant_index, .. } => {
+ Some(adt_def.variant(variant_index))
+ }
+ _ => self.ty.ty_adt_def().and_then(|adt| {
+ if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None }
+ }),
+ };
+
+ if let Some(variant) = variant {
+ write!(f, "{}", variant.name)?;
+
+ // Only for Adt we can have `S {...}`,
+ // which we handle separately here.
+ if variant.ctor_kind == CtorKind::Fictive {
+ write!(f, " {{ ")?;
+
+ let mut printed = 0;
+ for p in subpatterns {
+ if let PatKind::Wild = *p.pattern.kind {
+ continue;
+ }
+ let name = variant.fields[p.field.index()].name;
+ write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+ printed += 1;
+ }
+
+ if printed < variant.fields.len() {
+ write!(f, "{}..", start_or_comma())?;
+ }
+
+ return write!(f, " }}");
+ }
+ }
+
+ let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
+ if num_fields != 0 || variant.is_none() {
+ write!(f, "(")?;
+ for i in 0..num_fields {
+ write!(f, "{}", start_or_comma())?;
+
+ // Common case: the field is where we expect it.
+ if let Some(p) = subpatterns.get(i) {
+ if p.field.index() == i {
+ write!(f, "{}", p.pattern)?;
+ continue;
+ }
+ }
+
+ // Otherwise, we have to go looking for it.
+ if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+ write!(f, "{}", p.pattern)?;
+ } else {
+ write!(f, "_")?;
+ }
+ }
+ write!(f, ")")?;
+ }
+
+ Ok(())
+ }
+ PatKind::Deref { ref subpattern } => {
+ match self.ty.kind() {
+ ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
+ ty::Ref(_, _, mutbl) => {
+ write!(f, "&{}", mutbl.prefix_str())?;
+ }
+ _ => bug!("{} is a bad Deref pattern type", self.ty),
+ }
+ write!(f, "{}", subpattern)
+ }
+ PatKind::Constant { value } => write!(f, "{}", value),
+ PatKind::Range(PatRange { lo, hi, end }) => {
+ write!(f, "{}", lo)?;
+ write!(f, "{}", end)?;
+ write!(f, "{}", hi)
+ }
+ PatKind::Slice { ref prefix, ref slice, ref suffix }
+ | PatKind::Array { ref prefix, ref slice, ref suffix } => {
+ write!(f, "[")?;
+ for p in prefix {
+ write!(f, "{}{}", start_or_comma(), p)?;
+ }
+ if let Some(ref slice) = *slice {
+ write!(f, "{}", start_or_comma())?;
+ match *slice.kind {
+ PatKind::Wild => {}
+ _ => write!(f, "{}", slice)?,
+ }
+ write!(f, "..")?;
+ }
+ for p in suffix {
+ write!(f, "{}{}", start_or_comma(), p)?;
+ }
+ write!(f, "]")
+ }
+ PatKind::Or { ref pats } => {
+ for pat in pats {
+ write!(f, "{}{}", start_or_continue(" | "), pat)?;
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ // These are in alphabetical order, which is easy to maintain.
+ rustc_data_structures::static_assert_size!(Block, 56);
+ rustc_data_structures::static_assert_size!(Expr<'_>, 104);
+ rustc_data_structures::static_assert_size!(Pat<'_>, 24);
+ rustc_data_structures::static_assert_size!(Stmt<'_>, 120);
+}
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
new file mode 100644
index 000000000..97249fdd1
--- /dev/null
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -0,0 +1,244 @@
+use super::{
+ Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
+};
+
+pub trait Visitor<'a, 'tcx: 'a>: Sized {
+ fn thir(&self) -> &'a Thir<'tcx>;
+
+ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
+ walk_expr(self, expr);
+ }
+
+ fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
+ walk_stmt(self, stmt);
+ }
+
+ fn visit_block(&mut self, block: &Block) {
+ walk_block(self, block);
+ }
+
+ fn visit_arm(&mut self, arm: &Arm<'tcx>) {
+ walk_arm(self, arm);
+ }
+
+ fn visit_pat(&mut self, pat: &Pat<'tcx>) {
+ walk_pat(self, pat);
+ }
+
+ // Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
+ // (even though these types occur in THIR) for consistency and to reduce confusion,
+ // since the lazy creation of constants during thir construction causes most
+ // 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
+ // stage (they are mostly still identified by `DefId` or `hir::Lit`, see
+ // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
+ // You have to manually visit `ty::Const` and `mir::ConstantKind` through the
+ // other `visit*` functions.
+}
+
+pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
+ use ExprKind::*;
+ match expr.kind {
+ Scope { value, region_scope: _, lint_level: _ } => {
+ visitor.visit_expr(&visitor.thir()[value])
+ }
+ Box { value } => visitor.visit_expr(&visitor.thir()[value]),
+ If { cond, then, else_opt, if_then_scope: _ } => {
+ visitor.visit_expr(&visitor.thir()[cond]);
+ visitor.visit_expr(&visitor.thir()[then]);
+ if let Some(else_expr) = else_opt {
+ visitor.visit_expr(&visitor.thir()[else_expr]);
+ }
+ }
+ Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
+ visitor.visit_expr(&visitor.thir()[fun]);
+ for &arg in &**args {
+ visitor.visit_expr(&visitor.thir()[arg]);
+ }
+ }
+ Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
+ Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
+ visitor.visit_expr(&visitor.thir()[lhs]);
+ visitor.visit_expr(&visitor.thir()[rhs]);
+ }
+ Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+ Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
+ Use { source } => visitor.visit_expr(&visitor.thir()[source]),
+ NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
+ Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
+ Let { expr, .. } => {
+ visitor.visit_expr(&visitor.thir()[expr]);
+ }
+ Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
+ Match { scrutinee, ref arms } => {
+ visitor.visit_expr(&visitor.thir()[scrutinee]);
+ for &arm in &**arms {
+ visitor.visit_arm(&visitor.thir()[arm]);
+ }
+ }
+ Block { ref body } => visitor.visit_block(body),
+ Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
+ visitor.visit_expr(&visitor.thir()[lhs]);
+ visitor.visit_expr(&visitor.thir()[rhs]);
+ }
+ Field { lhs, variant_index: _, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
+ Index { lhs, index } => {
+ visitor.visit_expr(&visitor.thir()[lhs]);
+ visitor.visit_expr(&visitor.thir()[index]);
+ }
+ VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
+ Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+ AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+ Break { value, label: _ } => {
+ if let Some(value) = value {
+ visitor.visit_expr(&visitor.thir()[value])
+ }
+ }
+ Continue { label: _ } => {}
+ Return { value } => {
+ if let Some(value) = value {
+ visitor.visit_expr(&visitor.thir()[value])
+ }
+ }
+ ConstBlock { did: _, substs: _ } => {}
+ Repeat { value, count: _ } => {
+ visitor.visit_expr(&visitor.thir()[value]);
+ }
+ Array { ref fields } | Tuple { ref fields } => {
+ for &field in &**fields {
+ visitor.visit_expr(&visitor.thir()[field]);
+ }
+ }
+ Adt(box crate::thir::Adt {
+ ref fields,
+ ref base,
+ adt_def: _,
+ variant_index: _,
+ substs: _,
+ user_ty: _,
+ }) => {
+ for field in &**fields {
+ visitor.visit_expr(&visitor.thir()[field.expr]);
+ }
+ if let Some(base) = base {
+ visitor.visit_expr(&visitor.thir()[base.base]);
+ }
+ }
+ PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
+ visitor.visit_expr(&visitor.thir()[source])
+ }
+ Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
+ Literal { lit: _, neg: _ } => {}
+ NonHirLiteral { lit: _, user_ty: _ } => {}
+ ZstLiteral { user_ty: _ } => {}
+ NamedConst { def_id: _, substs: _, user_ty: _ } => {}
+ ConstParam { param: _, def_id: _ } => {}
+ StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
+ InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
+ for op in &**operands {
+ use InlineAsmOperand::*;
+ match op {
+ In { expr, reg: _ }
+ | Out { expr: Some(expr), reg: _, late: _ }
+ | InOut { expr, reg: _, late: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
+ SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
+ visitor.visit_expr(&visitor.thir()[*in_expr]);
+ if let Some(out_expr) = out_expr {
+ visitor.visit_expr(&visitor.thir()[*out_expr]);
+ }
+ }
+ Out { expr: None, reg: _, late: _ }
+ | Const { value: _, span: _ }
+ | SymFn { value: _, span: _ }
+ | SymStatic { def_id: _ } => {}
+ }
+ }
+ }
+ ThreadLocalRef(_) => {}
+ Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
+ }
+}
+
+pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
+ match &stmt.kind {
+ StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
+ StmtKind::Let {
+ initializer,
+ remainder_scope: _,
+ init_scope: _,
+ ref pattern,
+ lint_level: _,
+ else_block,
+ } => {
+ if let Some(init) = initializer {
+ visitor.visit_expr(&visitor.thir()[*init]);
+ }
+ visitor.visit_pat(pattern);
+ if let Some(block) = else_block {
+ visitor.visit_block(block)
+ }
+ }
+ }
+}
+
+pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
+ for &stmt in &*block.stmts {
+ visitor.visit_stmt(&visitor.thir()[stmt]);
+ }
+ if let Some(expr) = block.expr {
+ visitor.visit_expr(&visitor.thir()[expr]);
+ }
+}
+
+pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
+ match arm.guard {
+ Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
+ Some(Guard::IfLet(ref pat, expr)) => {
+ visitor.visit_pat(pat);
+ visitor.visit_expr(&visitor.thir()[expr]);
+ }
+ None => {}
+ }
+ visitor.visit_pat(&arm.pattern);
+ visitor.visit_expr(&visitor.thir()[arm.body]);
+}
+
+pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
+ use PatKind::*;
+ match pat.kind.as_ref() {
+ AscribeUserType { subpattern, ascription: _ }
+ | Deref { subpattern }
+ | Binding {
+ subpattern: Some(subpattern),
+ mutability: _,
+ mode: _,
+ var: _,
+ ty: _,
+ is_primary: _,
+ name: _,
+ } => visitor.visit_pat(&subpattern),
+ Binding { .. } | Wild => {}
+ Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => {
+ for subpattern in subpatterns {
+ visitor.visit_pat(&subpattern.pattern);
+ }
+ }
+ Constant { value: _ } => {}
+ Range(_) => {}
+ Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
+ for subpattern in prefix {
+ visitor.visit_pat(&subpattern);
+ }
+ if let Some(pat) = slice {
+ visitor.visit_pat(pat);
+ }
+ for subpattern in suffix {
+ visitor.visit_pat(&subpattern);
+ }
+ }
+ Or { pats } => {
+ for pat in pats {
+ visitor.visit_pat(&pat);
+ }
+ }
+ };
+}
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
new file mode 100644
index 000000000..6d4af8bea
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -0,0 +1,403 @@
+//! Types required for Chalk-related queries
+//!
+//! The primary purpose of this file is defining an implementation for the
+//! `chalk_ir::interner::Interner` trait. The primary purpose of this trait, as
+//! its name suggest, is to provide an abstraction boundary for creating
+//! interned Chalk types.
+
+use rustc_middle::ty::{self, AdtDef, TyCtxt};
+
+use rustc_hir::def_id::DefId;
+use rustc_target::spec::abi::Abi;
+
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+
+#[derive(Copy, Clone)]
+pub struct RustInterner<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+}
+
+/// We don't ever actually need this. It's only required for derives.
+impl<'tcx> Hash for RustInterner<'tcx> {
+ fn hash<H: Hasher>(&self, _state: &mut H) {}
+}
+
+/// We don't ever actually need this. It's only required for derives.
+impl<'tcx> Ord for RustInterner<'tcx> {
+ fn cmp(&self, _other: &Self) -> Ordering {
+ Ordering::Equal
+ }
+}
+
+/// We don't ever actually need this. It's only required for derives.
+impl<'tcx> PartialOrd for RustInterner<'tcx> {
+ fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
+ None
+ }
+}
+
+/// We don't ever actually need this. It's only required for derives.
+impl<'tcx> PartialEq for RustInterner<'tcx> {
+ fn eq(&self, _other: &Self) -> bool {
+ false
+ }
+}
+
+/// We don't ever actually need this. It's only required for derives.
+impl<'tcx> Eq for RustInterner<'tcx> {}
+
+impl fmt::Debug for RustInterner<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "RustInterner")
+ }
+}
+
+// Right now, there is no interning at all. I was running into problems with
+// adding interning in `ty/context.rs` for Chalk types with
+// `parallel-compiler = true`. -jackh726
+impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
+ type InternedType = Box<chalk_ir::TyData<Self>>;
+ type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>;
+ type InternedConst = Box<chalk_ir::ConstData<Self>>;
+ type InternedConcreteConst = ty::ValTree<'tcx>;
+ type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>;
+ type InternedGoal = Box<chalk_ir::GoalData<Self>>;
+ type InternedGoals = Vec<chalk_ir::Goal<Self>>;
+ type InternedSubstitution = Vec<chalk_ir::GenericArg<Self>>;
+ type InternedProgramClause = Box<chalk_ir::ProgramClauseData<Self>>;
+ type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>;
+ type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
+ type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
+ type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
+ type InternedVariances = Vec<chalk_ir::Variance>;
+ type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
+ type DefId = DefId;
+ type InternedAdtId = AdtDef<'tcx>;
+ type Identifier = ();
+ type FnAbi = Abi;
+
+ fn debug_program_clause_implication(
+ pci: &chalk_ir::ProgramClauseImplication<Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ let mut write = || {
+ write!(fmt, "{:?}", pci.consequence)?;
+
+ let conditions = pci.conditions.interned();
+ let constraints = pci.constraints.interned();
+
+ let conds = conditions.len();
+ let consts = constraints.len();
+ if conds == 0 && consts == 0 {
+ return Ok(());
+ }
+
+ write!(fmt, " :- ")?;
+
+ if conds != 0 {
+ for cond in &conditions[..conds - 1] {
+ write!(fmt, "{:?}, ", cond)?;
+ }
+ write!(fmt, "{:?}", conditions[conds - 1])?;
+ }
+
+ if conds != 0 && consts != 0 {
+ write!(fmt, " ; ")?;
+ }
+
+ if consts != 0 {
+ for constraint in &constraints[..consts - 1] {
+ write!(fmt, "{:?}, ", constraint)?;
+ }
+ write!(fmt, "{:?}", constraints[consts - 1])?;
+ }
+
+ Ok(())
+ };
+ Some(write())
+ }
+
+ fn debug_substitution(
+ substitution: &chalk_ir::Substitution<Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ Some(write!(fmt, "{:?}", substitution.interned()))
+ }
+
+ fn debug_separator_trait_ref(
+ separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ let substitution = &separator_trait_ref.trait_ref.substitution;
+ let parameters = substitution.interned();
+ Some(write!(
+ fmt,
+ "{:?}{}{:?}{:?}",
+ parameters[0],
+ separator_trait_ref.separator,
+ separator_trait_ref.trait_ref.trait_id,
+ chalk_ir::debug::Angle(&parameters[1..])
+ ))
+ }
+
+ fn debug_quantified_where_clauses(
+ clauses: &chalk_ir::QuantifiedWhereClauses<Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ Some(write!(fmt, "{:?}", clauses.interned()))
+ }
+
+ fn debug_ty(ty: &chalk_ir::Ty<Self>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
+ match &ty.interned().kind {
+ chalk_ir::TyKind::Ref(chalk_ir::Mutability::Not, lifetime, ty) => {
+ Some(write!(fmt, "(&{:?} {:?})", lifetime, ty))
+ }
+ chalk_ir::TyKind::Ref(chalk_ir::Mutability::Mut, lifetime, ty) => {
+ Some(write!(fmt, "(&{:?} mut {:?})", lifetime, ty))
+ }
+ chalk_ir::TyKind::Array(ty, len) => Some(write!(fmt, "[{:?}; {:?}]", ty, len)),
+ chalk_ir::TyKind::Slice(ty) => Some(write!(fmt, "[{:?}]", ty)),
+ chalk_ir::TyKind::Tuple(len, substs) => Some((|| {
+ write!(fmt, "(")?;
+ for (idx, substitution) in substs.interned().iter().enumerate() {
+ if idx == *len && *len != 1 {
+ // Don't add a trailing comma if the tuple has more than one element
+ write!(fmt, "{:?}", substitution)?;
+ } else {
+ write!(fmt, "{:?},", substitution)?;
+ }
+ }
+ write!(fmt, ")")
+ })()),
+ _ => None,
+ }
+ }
+
+ fn debug_alias(
+ alias_ty: &chalk_ir::AliasTy<Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ match alias_ty {
+ chalk_ir::AliasTy::Projection(projection_ty) => {
+ Self::debug_projection_ty(projection_ty, fmt)
+ }
+ chalk_ir::AliasTy::Opaque(opaque_ty) => Self::debug_opaque_ty(opaque_ty, fmt),
+ }
+ }
+
+ fn debug_projection_ty(
+ projection_ty: &chalk_ir::ProjectionTy<Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ Some(write!(
+ fmt,
+ "projection: {:?} {:?}",
+ projection_ty.associated_ty_id, projection_ty.substitution,
+ ))
+ }
+
+ fn debug_opaque_ty(
+ opaque_ty: &chalk_ir::OpaqueTy<Self>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Option<fmt::Result> {
+ Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id))
+ }
+
+ fn intern_ty(self, ty: chalk_ir::TyKind<Self>) -> Self::InternedType {
+ let flags = ty.compute_flags(self);
+ Box::new(chalk_ir::TyData { kind: ty, flags: flags })
+ }
+
+ fn ty_data<'a>(self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData<Self> {
+ ty
+ }
+
+ fn intern_lifetime(self, lifetime: chalk_ir::LifetimeData<Self>) -> Self::InternedLifetime {
+ Box::new(lifetime)
+ }
+
+ fn lifetime_data<'a>(
+ self,
+ lifetime: &'a Self::InternedLifetime,
+ ) -> &'a chalk_ir::LifetimeData<Self> {
+ &lifetime
+ }
+
+ fn intern_const(self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst {
+ Box::new(constant)
+ }
+
+ fn const_data<'a>(self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> {
+ &constant
+ }
+
+ fn const_eq(
+ self,
+ _ty: &Self::InternedType,
+ c1: &Self::InternedConcreteConst,
+ c2: &Self::InternedConcreteConst,
+ ) -> bool {
+ c1 == c2
+ }
+
+ fn intern_generic_arg(self, data: chalk_ir::GenericArgData<Self>) -> Self::InternedGenericArg {
+ Box::new(data)
+ }
+
+ fn generic_arg_data<'a>(
+ self,
+ data: &'a Self::InternedGenericArg,
+ ) -> &'a chalk_ir::GenericArgData<Self> {
+ &data
+ }
+
+ fn intern_goal(self, goal: chalk_ir::GoalData<Self>) -> Self::InternedGoal {
+ Box::new(goal)
+ }
+
+ fn goal_data<'a>(self, goal: &'a Self::InternedGoal) -> &'a chalk_ir::GoalData<Self> {
+ &goal
+ }
+
+ fn intern_goals<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::Goal<Self>, E>>,
+ ) -> Result<Self::InternedGoals, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn goals_data<'a>(self, goals: &'a Self::InternedGoals) -> &'a [chalk_ir::Goal<Self>] {
+ goals
+ }
+
+ fn intern_substitution<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::GenericArg<Self>, E>>,
+ ) -> Result<Self::InternedSubstitution, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn substitution_data<'a>(
+ self,
+ substitution: &'a Self::InternedSubstitution,
+ ) -> &'a [chalk_ir::GenericArg<Self>] {
+ substitution
+ }
+
+ fn intern_program_clause(
+ self,
+ data: chalk_ir::ProgramClauseData<Self>,
+ ) -> Self::InternedProgramClause {
+ Box::new(data)
+ }
+
+ fn program_clause_data<'a>(
+ self,
+ clause: &'a Self::InternedProgramClause,
+ ) -> &'a chalk_ir::ProgramClauseData<Self> {
+ &clause
+ }
+
+ fn intern_program_clauses<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>,
+ ) -> Result<Self::InternedProgramClauses, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn program_clauses_data<'a>(
+ self,
+ clauses: &'a Self::InternedProgramClauses,
+ ) -> &'a [chalk_ir::ProgramClause<Self>] {
+ clauses
+ }
+
+ fn intern_quantified_where_clauses<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>,
+ ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn quantified_where_clauses_data<'a>(
+ self,
+ clauses: &'a Self::InternedQuantifiedWhereClauses,
+ ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] {
+ clauses
+ }
+
+ fn intern_generic_arg_kinds<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>,
+ ) -> Result<Self::InternedVariableKinds, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn variable_kinds_data<'a>(
+ self,
+ parameter_kinds: &'a Self::InternedVariableKinds,
+ ) -> &'a [chalk_ir::VariableKind<Self>] {
+ parameter_kinds
+ }
+
+ fn intern_canonical_var_kinds<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>,
+ ) -> Result<Self::InternedCanonicalVarKinds, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn canonical_var_kinds_data<'a>(
+ self,
+ canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
+ ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
+ canonical_var_kinds
+ }
+
+ fn intern_constraints<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>,
+ ) -> Result<Self::InternedConstraints, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn constraints_data<'a>(
+ self,
+ constraints: &'a Self::InternedConstraints,
+ ) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] {
+ constraints
+ }
+
+ fn intern_variances<E>(
+ self,
+ data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
+ ) -> Result<Self::InternedVariances, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn variances_data<'a>(
+ self,
+ variances: &'a Self::InternedVariances,
+ ) -> &'a [chalk_ir::Variance] {
+ variances
+ }
+}
+
+impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> {
+ type Interner = Self;
+}
+
+/// A chalk environment and goal.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)]
+pub struct ChalkEnvironmentAndGoal<'tcx> {
+ pub environment: &'tcx ty::List<ty::Predicate<'tcx>>,
+ pub goal: ty::Predicate<'tcx>,
+}
+
+impl<'tcx> fmt::Display for ChalkEnvironmentAndGoal<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "environment: {:?}, goal: {}", self.environment, self.goal)
+ }
+}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
new file mode 100644
index 000000000..72b848c3e
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -0,0 +1,1026 @@
+//! Trait Resolution. See the [rustc dev guide] for more information on how this works.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
+
+mod chalk;
+pub mod query;
+pub mod select;
+pub mod specialization_graph;
+mod structural_impls;
+pub mod util;
+
+use crate::infer::canonical::Canonical;
+use crate::ty::abstract_const::NotConstEvaluatable;
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt};
+
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+use smallvec::SmallVec;
+
+use std::borrow::Cow;
+use std::hash::{Hash, Hasher};
+
+pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
+
+pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>;
+
+pub use self::ObligationCauseCode::*;
+
+pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner};
+
+/// 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:
+ ///
+ /// ```compile_fail,E0308
+ /// #![feature(specialization)]
+ /// trait Assoc {
+ /// type Output;
+ /// }
+ ///
+ /// impl<T> Assoc for T {
+ /// default type Output = bool;
+ /// }
+ ///
+ /// fn main() {
+ /// let x: <() as Assoc>::Output = true;
+ /// }
+ /// ```
+ ///
+ /// We also do not reveal the hidden type of opaque types during
+ /// type-checking.
+ 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 auto traits 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.
+///
+/// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the
+/// best trade-off between keeping the type small (which makes copies cheaper)
+/// while not doing too many heap allocations.
+///
+/// We do not want to intern this as there are a lot of obligation causes which
+/// only live for a short period of time.
+#[derive(Clone, Debug, PartialEq, Eq, Lift)]
+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,
+
+ code: InternedObligationCauseCode<'tcx>,
+}
+
+// This custom hash function speeds up hashing for `Obligation` deduplication
+// greatly by skipping the `code` field, which can be large and complex. That
+// shouldn't affect hash quality much since there are several other fields in
+// `Obligation` which should be unique enough, especially the predicate itself
+// which is hashed as an interned pointer. See #90996.
+impl Hash for ObligationCause<'_> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.body_id.hash(state);
+ self.span.hash(state);
+ }
+}
+
+impl<'tcx> ObligationCause<'tcx> {
+ #[inline]
+ pub fn new(
+ span: Span,
+ body_id: hir::HirId,
+ code: ObligationCauseCode<'tcx>,
+ ) -> ObligationCause<'tcx> {
+ ObligationCause { span, body_id, code: code.into() }
+ }
+
+ pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
+ ObligationCause::new(span, body_id, MiscObligation)
+ }
+
+ #[inline(always)]
+ pub fn dummy() -> ObligationCause<'tcx> {
+ ObligationCause::dummy_with_span(DUMMY_SP)
+ }
+
+ #[inline(always)]
+ pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
+ ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() }
+ }
+
+ pub fn span(&self) -> Span {
+ match *self.code() {
+ ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+ arm_span,
+ ..
+ }) => arm_span,
+ _ => self.span,
+ }
+ }
+
+ #[inline]
+ pub fn code(&self) -> &ObligationCauseCode<'tcx> {
+ &self.code
+ }
+
+ pub fn map_code(
+ &mut self,
+ f: impl FnOnce(InternedObligationCauseCode<'tcx>) -> ObligationCauseCode<'tcx>,
+ ) {
+ self.code = f(std::mem::take(&mut self.code)).into();
+ }
+
+ pub fn derived_cause(
+ mut self,
+ parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+ ) -> ObligationCause<'tcx> {
+ /*!
+ * Creates a cause for obligations that are derived from
+ * `obligation` by a recursive search (e.g., for a builtin
+ * bound, or eventually a `auto trait Foo`). If `obligation`
+ * is itself a derived obligation, this is just a clone, but
+ * otherwise we create a "derived obligation" cause so as to
+ * keep track of the original root obligation for error
+ * reporting.
+ */
+
+ // NOTE(flaper87): As of now, it keeps track of the whole error
+ // chain. Ideally, we should have a way to configure this either
+ // by using -Z verbose or just a CLI argument.
+ self.code =
+ variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into();
+ self
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+pub struct UnifyReceiverContext<'tcx> {
+ pub assoc_item: ty::AssocItem,
+ pub param_env: ty::ParamEnv<'tcx>,
+ pub substs: SubstsRef<'tcx>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, Default)]
+pub struct InternedObligationCauseCode<'tcx> {
+ /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
+ /// the time). `Some` otherwise.
+ code: Option<Lrc<ObligationCauseCode<'tcx>>>,
+}
+
+impl<'tcx> ObligationCauseCode<'tcx> {
+ #[inline(always)]
+ fn into(self) -> InternedObligationCauseCode<'tcx> {
+ InternedObligationCauseCode {
+ code: if let ObligationCauseCode::MiscObligation = self {
+ None
+ } else {
+ Some(Lrc::new(self))
+ },
+ }
+ }
+}
+
+impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
+ type Target = ObligationCauseCode<'tcx>;
+
+ fn deref(&self) -> &Self::Target {
+ self.code.as_deref().unwrap_or(&ObligationCauseCode::MiscObligation)
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+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(/* Concrete type */ Ty<'tcx>, /* 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(Option<Span>),
+ /// Return type must be `Sized`.
+ SizedReturnType,
+ /// Yield type must be `Sized`.
+ SizedYieldType,
+ /// Box expression result type must be `Sized`.
+ SizedBoxType,
+ /// Inline asm operand type must be `Sized`.
+ InlineAsmSized,
+ /// `[expr; N]` requires `type_of(expr): Copy`.
+ RepeatElementCopy {
+ /// If element is a `const fn` we display a help message suggesting to move the
+ /// function call to a new `const` item while saying that `T` doesn't implement `Copy`.
+ is_const_fn: bool,
+ },
+
+ /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
+ FieldSized {
+ adt_kind: AdtKind,
+ span: Span,
+ last: bool,
+ },
+
+ /// Constant expressions must be sized.
+ ConstSized,
+
+ /// `static` items must have `Sync` type.
+ SharedStatic,
+
+ BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
+
+ ImplDerivedObligation(Box<ImplDerivedObligationCause<'tcx>>),
+
+ DerivedObligation(DerivedObligationCause<'tcx>),
+
+ FunctionArgumentObligation {
+ /// The node of the relevant argument in the function call.
+ arg_hir_id: hir::HirId,
+ /// The node of the function call.
+ call_hir_id: hir::HirId,
+ /// The obligation introduced by this argument.
+ parent_code: InternedObligationCauseCode<'tcx>,
+ },
+
+ /// Error derived when matching traits/impls; see ObligationCause for more details
+ CompareImplItemObligation {
+ impl_item_def_id: LocalDefId,
+ trait_item_def_id: DefId,
+ kind: ty::AssocKind,
+ },
+
+ /// Checking that the bounds of a trait's associated type hold for a given impl
+ CheckAssociatedTypeBounds {
+ impl_item_def_id: LocalDefId,
+ trait_item_def_id: DefId,
+ },
+
+ /// Checking that this expression can be assigned to its target.
+ 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<'tcx>>),
+
+ /// 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,
+
+ /// A let else block does not diverge
+ LetElse,
+
+ /// Method receiver
+ MethodReceiver,
+
+ UnifyReceiver(Box<UnifyReceiverContext<'tcx>>),
+
+ /// `return` with no expression
+ ReturnNoExpression,
+
+ /// `return` with an expression
+ ReturnValue(hir::HirId),
+
+ /// Return type of this function
+ ReturnType,
+
+ /// Opaque return type of this function
+ OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
+
+ /// Block implicit return
+ BlockTailExpression(hir::HirId),
+
+ /// #[feature(trivial_bounds)] is not enabled
+ TrivialBound,
+
+ /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
+ OpaqueType,
+
+ AwaitableExpr(Option<hir::HirId>),
+
+ ForLoopIterator,
+
+ QuestionMark,
+
+ /// Well-formed checking. If a `WellFormedLoc` is provided,
+ /// then it will be used to perform HIR-based wf checking
+ /// after an error occurs, in order to generate a more precise error span.
+ /// This is purely for diagnostic purposes - it is always
+ /// correct to use `MiscObligation` instead, or to specify
+ /// `WellFormed(None)`
+ WellFormed(Option<WellFormedLoc>),
+
+ /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against.
+ MatchImpl(ObligationCause<'tcx>, DefId),
+
+ BinOp {
+ rhs_span: Option<Span>,
+ is_lit: bool,
+ output_pred: Option<Predicate<'tcx>>,
+ },
+}
+
+/// The 'location' at which we try to perform HIR-based wf checking.
+/// This information is used to obtain an `hir::Ty`, which
+/// we can walk in order to obtain precise spans for any
+/// 'nested' types (e.g. `Foo` in `Option<Foo>`).
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum WellFormedLoc {
+ /// Use the type of the provided definition.
+ Ty(LocalDefId),
+ /// Use the type of the parameter of the provided function.
+ /// We cannot use `hir::Param`, since the function may
+ /// not have a body (e.g. a trait method definition)
+ Param {
+ /// The function to lookup the parameter in
+ function: LocalDefId,
+ /// The index of the parameter to use.
+ /// Parameters are indexed from 0, with the return type
+ /// being the last 'parameter'
+ param_idx: u16,
+ },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+pub struct ImplDerivedObligationCause<'tcx> {
+ pub derived: DerivedObligationCause<'tcx>,
+ pub impl_def_id: DefId,
+ pub span: Span,
+}
+
+impl<'tcx> ObligationCauseCode<'tcx> {
+ // Return the base obligation, ignoring derived obligations.
+ pub fn peel_derives(&self) -> &Self {
+ let mut base_cause = self;
+ while let Some((parent_code, _)) = base_cause.parent() {
+ base_cause = parent_code;
+ }
+ base_cause
+ }
+
+ pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
+ match self {
+ FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)),
+ BuiltinDerivedObligation(derived)
+ | DerivedObligation(derived)
+ | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => {
+ Some((&derived.parent_code, Some(derived.parent_trait_pred)))
+ }
+ _ => None,
+ }
+ }
+}
+
+// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ObligationCauseCode<'_>, 48);
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum StatementAsExpression {
+ CorrectType,
+ NeedsBoxing,
+}
+
+impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
+ type Lifted = StatementAsExpression;
+ fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
+ Some(self)
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+pub struct MatchExpressionArmCause<'tcx> {
+ pub arm_block_id: Option<hir::HirId>,
+ pub arm_ty: Ty<'tcx>,
+ pub arm_span: Span,
+ pub prior_arm_block_id: Option<hir::HirId>,
+ pub prior_arm_ty: Ty<'tcx>,
+ pub prior_arm_span: Span,
+ pub scrut_span: Span,
+ pub source: hir::MatchSource,
+ pub prior_arms: Vec<Span>,
+ pub scrut_hir_id: hir::HirId,
+ pub opt_suggest_box_span: Option<Span>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Lift, TypeFoldable, TypeVisitable)]
+pub struct IfExpressionCause<'tcx> {
+ pub then_id: hir::HirId,
+ pub else_id: hir::HirId,
+ pub then_ty: Ty<'tcx>,
+ pub else_ty: Ty<'tcx>,
+ pub outer_span: Option<Span>,
+ pub opt_suggest_box_span: Option<Span>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+pub struct DerivedObligationCause<'tcx> {
+ /// The trait predicate 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 predicate here
+ /// directly.
+ pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+
+ /// The parent trait had this cause.
+ pub parent_code: InternedObligationCauseCode<'tcx>,
+}
+
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
+pub enum SelectionError<'tcx> {
+ /// The trait is not implemented.
+ Unimplemented,
+ /// After a closure impl has selected, its "outputs" were evaluated
+ /// (which for closures includes the "input" type params) and they
+ /// didn't resolve. See `confirm_poly_trait_refs` for more.
+ OutputTypeParameterMismatch(
+ ty::PolyTraitRef<'tcx>,
+ ty::PolyTraitRef<'tcx>,
+ ty::error::TypeError<'tcx>,
+ ),
+ /// The trait pointed by `DefId` is not object safe.
+ TraitNotObjectSafe(DefId),
+ /// A given constant couldn't be evaluated.
+ NotConstEvaluatable(NotConstEvaluatable),
+ /// Exceeded the recursion depth during type projection.
+ Overflow(OverflowError),
+ /// Signaling that an error has already been emitted, to avoid
+ /// multiple errors being shown.
+ ErrorReporting,
+ /// Multiple applicable `impl`s where found. The `DefId`s correspond to
+ /// all the `impl`s' Items.
+ Ambiguous(Vec<DefId>),
+}
+
+/// 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 `ImplSource`
+/// indicates where the impl comes from.
+///
+/// For example, the obligation may be satisfied by a specific impl (case A),
+/// or it may be relative to some bound that is in scope (case B).
+///
+/// ```ignore (illustrative)
+/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
+/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2
+/// impl Clone for i32 { ... } // Impl_3
+///
+/// fn foo<T: Clone>(concrete: Option<Box<i32>>, param: T, mixed: Option<T>) {
+/// // Case A: ImplSource points at a specific impl. Only possible when
+/// // type is concretely known. If the impl itself has bounded
+/// // type parameters, ImplSource will carry resolutions for those as well:
+/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
+///
+/// // Case A: ImplSource points at a specific impl. Only possible when
+/// // type is concretely known. If the impl itself has bounded
+/// // type parameters, ImplSource will carry resolutions for those as well:
+/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
+///
+/// // Case B: ImplSource must be provided by caller. This applies when
+/// // type is a type parameter.
+/// param.clone(); // ImplSource::Param
+///
+/// // Case C: A mix of cases A and B.
+/// mixed.clone(); // ImplSource(Impl_1, [ImplSource::Param])
+/// }
+/// ```
+///
+/// ### The type parameter `N`
+///
+/// See explanation on `ImplSourceUserDefinedData`.
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum ImplSource<'tcx, N> {
+ /// ImplSource identifying a particular impl.
+ UserDefined(ImplSourceUserDefinedData<'tcx, N>),
+
+ /// ImplSource 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.
+ AutoImpl(ImplSourceAutoImplData<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).
+ Param(Vec<N>, ty::BoundConstness),
+
+ /// Virtual calls through an object.
+ Object(ImplSourceObjectData<'tcx, N>),
+
+ /// Successful resolution for a builtin trait.
+ Builtin(ImplSourceBuiltinData<N>),
+
+ /// ImplSource for trait upcasting coercion
+ TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
+
+ /// ImplSource automatically generated for a closure. The `DefId` is the ID
+ /// of the closure expression. This is an `ImplSource::UserDefined` in spirit, but the
+ /// impl is generated by the compiler and does not appear in the source.
+ Closure(ImplSourceClosureData<'tcx, N>),
+
+ /// Same as above, but for a function pointer type with the given signature.
+ FnPointer(ImplSourceFnPointerData<'tcx, N>),
+
+ /// ImplSource for a builtin `DeterminantKind` trait implementation.
+ DiscriminantKind(ImplSourceDiscriminantKindData),
+
+ /// ImplSource for a builtin `Pointee` trait implementation.
+ Pointee(ImplSourcePointeeData),
+
+ /// ImplSource automatically generated for a generator.
+ Generator(ImplSourceGeneratorData<'tcx, N>),
+
+ /// ImplSource for a trait alias.
+ TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
+
+ /// ImplSource for a `const Drop` implementation.
+ ConstDestruct(ImplSourceConstDestructData<N>),
+}
+
+impl<'tcx, N> ImplSource<'tcx, N> {
+ pub fn nested_obligations(self) -> Vec<N> {
+ match self {
+ ImplSource::UserDefined(i) => i.nested,
+ ImplSource::Param(n, _) => n,
+ ImplSource::Builtin(i) => i.nested,
+ ImplSource::AutoImpl(d) => d.nested,
+ ImplSource::Closure(c) => c.nested,
+ ImplSource::Generator(c) => c.nested,
+ ImplSource::Object(d) => d.nested,
+ ImplSource::FnPointer(d) => d.nested,
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+ | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
+ ImplSource::TraitAlias(d) => d.nested,
+ ImplSource::TraitUpcasting(d) => d.nested,
+ ImplSource::ConstDestruct(i) => i.nested,
+ }
+ }
+
+ pub fn borrow_nested_obligations(&self) -> &[N] {
+ match &self {
+ ImplSource::UserDefined(i) => &i.nested[..],
+ ImplSource::Param(n, _) => &n,
+ ImplSource::Builtin(i) => &i.nested,
+ ImplSource::AutoImpl(d) => &d.nested,
+ ImplSource::Closure(c) => &c.nested,
+ ImplSource::Generator(c) => &c.nested,
+ ImplSource::Object(d) => &d.nested,
+ ImplSource::FnPointer(d) => &d.nested,
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+ | ImplSource::Pointee(ImplSourcePointeeData) => &[],
+ ImplSource::TraitAlias(d) => &d.nested,
+ ImplSource::TraitUpcasting(d) => &d.nested,
+ ImplSource::ConstDestruct(i) => &i.nested,
+ }
+ }
+
+ pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M>
+ where
+ F: FnMut(N) -> M,
+ {
+ match self {
+ ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData {
+ impl_def_id: i.impl_def_id,
+ substs: i.substs,
+ nested: i.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
+ ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData {
+ nested: i.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
+ upcast_trait_ref: o.upcast_trait_ref,
+ vtable_base: o.vtable_base,
+ nested: o.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData {
+ trait_def_id: d.trait_def_id,
+ nested: d.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData {
+ closure_def_id: c.closure_def_id,
+ substs: c.substs,
+ nested: c.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData {
+ generator_def_id: c.generator_def_id,
+ substs: c.substs,
+ nested: c.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData {
+ fn_ty: p.fn_ty,
+ nested: p.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+ }
+ ImplSource::Pointee(ImplSourcePointeeData) => {
+ ImplSource::Pointee(ImplSourcePointeeData)
+ }
+ ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
+ alias_def_id: d.alias_def_id,
+ substs: d.substs,
+ nested: d.nested.into_iter().map(f).collect(),
+ }),
+ ImplSource::TraitUpcasting(d) => {
+ ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
+ upcast_trait_ref: d.upcast_trait_ref,
+ vtable_vptr_slot: d.vtable_vptr_slot,
+ nested: d.nested.into_iter().map(f).collect(),
+ })
+ }
+ ImplSource::ConstDestruct(i) => {
+ ImplSource::ConstDestruct(ImplSourceConstDestructData {
+ nested: i.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, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceUserDefinedData<'tcx, N> {
+ pub impl_def_id: DefId,
+ pub substs: SubstsRef<'tcx>,
+ pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceGeneratorData<'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, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceClosureData<'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, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceAutoImplData<N> {
+ pub trait_def_id: DefId,
+ pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceTraitUpcastingData<'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, pointers to supertrait vtable will
+ /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
+ /// within that vtable.
+ pub vtable_vptr_slot: Option<usize>,
+
+ pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceBuiltinData<N> {
+ pub nested: Vec<N>,
+}
+
+#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceObjectData<'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, pointers to supertrait vtable will
+ /// be provided when necessary; 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, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceFnPointerData<'tcx, N> {
+ pub fn_ty: Ty<'tcx>,
+ pub nested: Vec<N>,
+}
+
+// FIXME(@lcnr): This should be refactored and merged with other builtin vtables.
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+pub struct ImplSourceDiscriminantKindData;
+
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+pub struct ImplSourcePointeeData;
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceConstDestructData<N> {
+ pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ImplSourceTraitAliasData<'tcx, N> {
+ pub alias_def_id: DefId,
+ pub substs: SubstsRef<'tcx>,
+ pub nested: Vec<N>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
+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(Symbol, MethodViolationCode, Span),
+
+ /// Associated const.
+ AssocConst(Symbol, Span),
+
+ /// GAT
+ GAT(Symbol, 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".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(),
+ ObjectSafetyViolation::GAT(name, _) => {
+ format!("it contains the generic associated type `{}`", name).into()
+ }
+ }
+ }
+
+ pub fn solution(&self, err: &mut Diagnostic) {
+ match self {
+ ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {}
+ ObjectSafetyViolation::Method(
+ name,
+ MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
+ _,
+ ) => {
+ err.span_suggestion(
+ add_self_sugg.1,
+ format!(
+ "consider turning `{}` into a method by giving it a `&self` argument",
+ name
+ ),
+ add_self_sugg.0.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion(
+ make_sized_sugg.1,
+ format!(
+ "alternatively, consider constraining `{}` so it does not apply to \
+ trait objects",
+ name
+ ),
+ make_sized_sugg.0.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ ObjectSafetyViolation::Method(
+ name,
+ MethodViolationCode::UndispatchableReceiver(Some(span)),
+ _,
+ ) => {
+ err.span_suggestion(
+ *span,
+ &format!(
+ "consider changing method `{}`'s `self` parameter to be `&self`",
+ name
+ ),
+ "&Self",
+ Applicability::MachineApplicable,
+ );
+ }
+ ObjectSafetyViolation::AssocConst(name, _)
+ | ObjectSafetyViolation::GAT(name, _)
+ | ObjectSafetyViolation::Method(name, ..) => {
+ err.help(&format!("consider moving `{}` to another trait", name));
+ }
+ }
+ }
+
+ 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::GAT(_, span)
+ | ObjectSafetyViolation::Method(_, _, span)
+ if *span != DUMMY_SP =>
+ {
+ smallvec![*span]
+ }
+ _ => smallvec![],
+ }
+ }
+}
+
+/// Reasons a method might not be object-safe.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
+pub enum MethodViolationCode {
+ /// e.g., `fn foo()`
+ StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>),
+
+ /// e.g., `fn foo(&self, x: Self)`
+ ReferencesSelfInput(Option<Span>),
+
+ /// 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(Option<Span>),
+}
+
+/// These are the error cases for `codegen_fulfill_obligation`.
+#[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
+pub enum CodegenObligationError {
+ /// Ambiguity can happen when monomorphizing during trans
+ /// expands to some humongous type that never occurred
+ /// statically -- this humongous type can then overflow,
+ /// leading to an ambiguous result. So report this as an
+ /// overflow bug, since I believe this is the only case
+ /// where ambiguity can result.
+ Ambiguity,
+ /// This can trigger when we probe for the source of a `'static` lifetime requirement
+ /// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+ /// This can also trigger when we have a global bound that is not actually satisfied,
+ /// but was included during typeck due to the trivial_bounds feature.
+ Unimplemented,
+ FulfillmentError,
+}
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
new file mode 100644
index 000000000..1f9b474ad
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -0,0 +1,230 @@
+//! 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
+//! `rustc_traits`.
+
+use crate::infer::canonical::{Canonical, QueryResponse};
+use crate::ty::error::TypeError;
+use crate::ty::subst::GenericArg;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_errors::struct_span_err;
+use rustc_span::source_map::Span;
+use std::iter::FromIterator;
+
+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, Lift)]
+ #[derive(TypeFoldable, TypeVisitable)]
+ 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, Lift)]
+ #[derive(TypeFoldable, TypeVisitable)]
+ pub struct Eq<'tcx> {
+ pub a: Ty<'tcx>,
+ pub b: Ty<'tcx>,
+ }
+
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+ #[derive(TypeFoldable, TypeVisitable)]
+ pub struct Subtype<'tcx> {
+ pub sub: Ty<'tcx>,
+ pub sup: Ty<'tcx>,
+ }
+
+ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+ #[derive(TypeFoldable, TypeVisitable)]
+ 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, Lift)]
+ #[derive(TypeFoldable, TypeVisitable)]
+ 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(Copy, 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, TypeVisitable, 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.get(0) {
+ 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 DropckConstraint<'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> DropckConstraint<'tcx> {
+ pub fn empty() -> DropckConstraint<'tcx> {
+ DropckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] }
+ }
+}
+
+impl<'tcx> FromIterator<DropckConstraint<'tcx>> for DropckConstraint<'tcx> {
+ fn from_iter<I: IntoIterator<Item = DropckConstraint<'tcx>>>(iter: I) -> Self {
+ let mut result = Self::empty();
+
+ for DropckConstraint { outlives, dtorck_types, overflows } in iter {
+ result.outlives.extend(outlives);
+ result.dtorck_types.extend(dtorck_types);
+ result.overflows.extend(overflows);
+ }
+
+ result
+ }
+}
+
+#[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(Copy, Clone, Debug, HashStable)]
+pub struct MethodAutoderefStepsResult<'tcx> {
+ /// The valid autoderef steps that could be find.
+ pub steps: &'tcx [CandidateStep<'tcx>],
+ /// If Some(T), a type autoderef reported an error on.
+ pub opt_bad_ty: Option<&'tcx 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, TypeVisitable, 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, TypeVisitable, Lift, HashStable)]
+pub enum OutlivesBound<'tcx> {
+ RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
+ RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
+ RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+}
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
new file mode 100644
index 000000000..e836ba47e
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -0,0 +1,312 @@
+//! Candidate selection. See the [rustc dev guide] for more information on how this works.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
+
+use self::EvaluationResult::*;
+
+use super::{SelectionError, SelectionResult};
+use rustc_errors::ErrorGuaranteed;
+
+use crate::ty;
+
+use rustc_hir::def_id::DefId;
+use rustc_query_system::cache::Cache;
+
+pub type SelectionCache<'tcx> = Cache<
+ // This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace
+ // caller bounds with an empty list if the `TraitPredicate` looks global, which may happen
+ // after erasing lifetimes from the predicate.
+ (ty::ParamEnv<'tcx>, ty::TraitPredicate<'tcx>),
+ SelectionResult<'tcx, SelectionCandidate<'tcx>>,
+>;
+
+pub type EvaluationCache<'tcx> = Cache<
+ // See above: this cache does not use `ParamEnvAnd` in its keys due to sometimes incorrectly
+ // caching with the wrong `ParamEnv`.
+ (ty::ParamEnv<'tcx>, ty::PolyTraitPredicate<'tcx>),
+ EvaluationResult,
+>;
+
+/// 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 `i32`. 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
+///
+/// ```rust, ignore
+/// 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:
+///
+/// ```rust, ignore
+/// 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, TypeVisitable)]
+pub enum SelectionCandidate<'tcx> {
+ BuiltinCandidate {
+ /// `false` if there are no *further* obligations.
+ has_nested: bool,
+ },
+
+ /// Implementation of transmutability trait.
+ TransmutabilityCandidate,
+
+ ParamCandidate(ty::PolyTraitPredicate<'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. The `usize` is an index
+ /// into the list returned by `tcx.item_bounds`.
+ ProjectionCandidate(usize),
+
+ /// Implementation of a `Fn`-family trait by one of the anonymous types
+ /// generated for an `||` 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 {
+ is_const: bool,
+ },
+
+ /// Builtin implementation of `DiscriminantKind`.
+ DiscriminantKindCandidate,
+
+ /// Builtin implementation of `Pointee`.
+ PointeeCandidate,
+
+ TraitAliasCandidate(DefId),
+
+ /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
+ /// position in the iterator returned by
+ /// `rustc_infer::traits::util::supertraits`.
+ ObjectCandidate(usize),
+
+ /// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
+ /// The index is the position in the iterator returned by
+ /// `rustc_infer::traits::util::supertraits`.
+ TraitUpcastingUnsizeCandidate(usize),
+
+ BuiltinObjectCandidate,
+
+ BuiltinUnsizeCandidate,
+
+ /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
+ ConstDestructCandidate(Option<DefId>),
+}
+
+/// 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 successful, but need to rerun because opaque types got
+ /// hidden types assigned without it being known whether the opaque types
+ /// are within their defining scope
+ EvaluatedToOkModuloOpaqueTypes,
+ /// 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 {
+ EvaluatedToOkModuloOpaqueTypes
+ | EvaluatedToOk
+ | EvaluatedToOkModuloRegions
+ | EvaluatedToAmbig
+ | EvaluatedToUnknown => true,
+
+ EvaluatedToErr | EvaluatedToRecur => false,
+ }
+ }
+
+ pub fn is_stack_dependent(self) -> bool {
+ match self {
+ EvaluatedToUnknown | EvaluatedToRecur => true,
+
+ EvaluatedToOkModuloOpaqueTypes
+ | EvaluatedToOk
+ | EvaluatedToOkModuloRegions
+ | EvaluatedToAmbig
+ | EvaluatedToErr => false,
+ }
+ }
+}
+
+/// Indicates that trait evaluation caused overflow and in which pass.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
+pub enum OverflowError {
+ Error(ErrorGuaranteed),
+ Canonical,
+ ErrorReporting,
+}
+
+impl From<ErrorGuaranteed> for OverflowError {
+ fn from(e: ErrorGuaranteed) -> OverflowError {
+ OverflowError::Error(e)
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ OverflowError,
+}
+
+impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
+ fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
+ match overflow_error {
+ OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)),
+ OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical),
+ OverflowError::ErrorReporting => SelectionError::ErrorReporting,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
new file mode 100644
index 000000000..2465f8e25
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -0,0 +1,261 @@
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::visit::TypeVisitable;
+use crate::ty::{self, TyCtxt};
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def_id::{DefId, DefIdMap};
+use rustc_span::symbol::sym;
+
+/// 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(TyEncodable, TyDecodable, HashStable, Debug)]
+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>,
+
+ /// Whether an error was emitted while constructing the graph.
+ pub has_errored: Option<ErrorGuaranteed>,
+}
+
+impl Graph {
+ pub fn new() -> Graph {
+ Graph { parent: Default::default(), children: Default::default(), has_errored: None }
+ }
+
+ /// 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))
+ }
+}
+
+/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
+/// purposes.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable, Debug, TyEncodable, TyDecodable)]
+pub enum OverlapMode {
+ /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
+ Stable,
+ /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
+ WithNegative,
+ /// Just check for negative impls, not for "where clause not implemented": used for testing.
+ Strict,
+}
+
+impl OverlapMode {
+ pub fn get<'tcx>(tcx: TyCtxt<'tcx>, trait_id: DefId) -> OverlapMode {
+ let with_negative_coherence = tcx.features().with_negative_coherence;
+ let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence);
+
+ if with_negative_coherence {
+ if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative }
+ } else if strict_coherence {
+ bug!("To use strict_coherence you need to set with_negative_coherence feature flag");
+ } else {
+ OverlapMode::Stable
+ }
+ }
+
+ pub fn use_negative_impl(&self) -> bool {
+ *self == OverlapMode::Strict || *self == OverlapMode::WithNegative
+ }
+
+ pub fn use_implicit_negative(&self) -> bool {
+ *self == OverlapMode::Stable || *self == OverlapMode::WithNegative
+ }
+}
+
+/// Children of a given impl, grouped into blanket/non-blanket varieties as is
+/// done in `TraitDef`.
+#[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)]
+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
+ // `non_blanket_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 non_blanket_impls: FxIndexMap<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 Node {
+ pub fn is_from_trait(&self) -> bool {
+ matches!(self, Node::Trait(..))
+ }
+
+ /// Trys to find the associated item that implements `trait_item_def_id`
+ /// defined in this node.
+ ///
+ /// If this returns `None`, the item can potentially still be found in
+ /// parents of this node.
+ pub fn item<'tcx>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ trait_item_def_id: DefId,
+ ) -> Option<&'tcx ty::AssocItem> {
+ match *self {
+ Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)),
+ Node::Impl(impl_def_id) => {
+ let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?;
+ Some(tcx.associated_item(*id))
+ }
+ }
+ }
+
+ 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
+ }
+}
+
+/// Information about the most specialized definition of an associated item.
+pub struct LeafDef {
+ /// The associated item described by this `LeafDef`.
+ pub item: ty::AssocItem,
+
+ /// The node in the specialization graph containing the definition of `item`.
+ pub defining_node: Node,
+
+ /// The "top-most" (ie. least specialized) specialization graph node that finalized the
+ /// definition of `item`.
+ ///
+ /// Example:
+ ///
+ /// ```
+ /// #![feature(specialization)]
+ /// trait Tr {
+ /// fn assoc(&self);
+ /// }
+ ///
+ /// impl<T> Tr for T {
+ /// default fn assoc(&self) {}
+ /// }
+ ///
+ /// impl Tr for u8 {}
+ /// ```
+ ///
+ /// If we start the leaf definition search at `impl Tr for u8`, that impl will be the
+ /// `finalizing_node`, while `defining_node` will be the generic impl.
+ ///
+ /// If the leaf definition search is started at the generic impl, `finalizing_node` will be
+ /// `None`, since the most specialized impl we found still allows overriding the method
+ /// (doesn't finalize it).
+ pub finalizing_node: Option<Node>,
+}
+
+impl LeafDef {
+ /// Returns whether this definition is known to not be further specializable.
+ pub fn is_final(&self) -> bool {
+ self.finalizing_node.is_some()
+ }
+}
+
+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_def_id: DefId) -> Option<LeafDef> {
+ let mut finalizing_node = None;
+
+ self.find_map(|node| {
+ if let Some(item) = node.item(tcx, trait_item_def_id) {
+ if finalizing_node.is_none() {
+ let is_specializable = item.defaultness(tcx).is_default()
+ || tcx.impl_defaultness(node.def_id()).is_default();
+
+ if !is_specializable {
+ finalizing_node = Some(node);
+ }
+ }
+
+ Some(LeafDef { item: *item, defining_node: node, finalizing_node })
+ } else {
+ // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
+ finalizing_node = Some(node);
+ None
+ }
+ })
+ }
+}
+
+/// Walk up the specialization ancestors of a given impl, starting with that
+/// impl itself.
+///
+/// Returns `Err` if an error was reported while building the specialization
+/// graph.
+pub fn ancestors<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ start_from_impl: DefId,
+) -> Result<Ancestors<'tcx>, ErrorGuaranteed> {
+ let specialization_graph = tcx.specialization_graph_of(trait_def_id);
+
+ if let Some(reported) = specialization_graph.has_errored {
+ Err(reported)
+ } else if let Some(reported) = tcx.type_of(start_from_impl).error_reported() {
+ Err(reported)
+ } else {
+ Ok(Ancestors {
+ trait_def_id,
+ specialization_graph,
+ current_source: Some(Node::Impl(start_from_impl)),
+ })
+ }
+}
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
new file mode 100644
index 000000000..7fbd57ac7
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -0,0 +1,135 @@
+use crate::traits;
+
+use std::fmt;
+
+// Structural impls for the structs in `traits`.
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v),
+
+ super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t),
+
+ super::ImplSource::Closure(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::Generator(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d),
+
+ super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::Param(ref n, ct) => {
+ write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
+ }
+
+ super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
+ }
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceUserDefinedData(impl_def_id={:?}, substs={:?}, nested={:?})",
+ self.impl_def_id, self.substs, self.nested
+ )
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceGeneratorData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
+ self.generator_def_id, self.substs, self.nested
+ )
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceClosureData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
+ self.closure_def_id, self.substs, self.nested
+ )
+ }
+}
+
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ImplSourceBuiltinData(nested={:?})", self.nested)
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
+ self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
+ )
+ }
+}
+
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceAutoImplData(trait_def_id={:?}, nested={:?})",
+ self.trait_def_id, self.nested
+ )
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceObjectData(upcast={:?}, vtable_base={}, nested={:?})",
+ self.upcast_trait_ref, self.vtable_base, self.nested
+ )
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFnPointerData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ImplSourceFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
+ }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceTraitAliasData(alias_def_id={:?}, substs={:?}, nested={:?})",
+ self.alias_def_id, self.substs, self.nested
+ )
+ }
+}
+
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ImplSourceConstDestructData(nested={:?})", self.nested)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Lift implementations
+
+TrivialTypeTraversalAndLiftImpls! {
+ super::ImplSourceDiscriminantKindData,
+ super::ImplSourcePointeeData,
+}
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
new file mode 100644
index 000000000..d54b8c599
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -0,0 +1,49 @@
+use rustc_data_structures::fx::FxHashSet;
+
+use crate::ty::{PolyTraitRef, TyCtxt};
+
+/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
+///
+/// A simplified version of the same function at `rustc_infer::traits::util::supertraits`.
+pub fn supertraits<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: PolyTraitRef<'tcx>,
+) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
+ Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
+}
+
+struct Elaborator<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ visited: FxHashSet<PolyTraitRef<'tcx>>,
+ stack: Vec<PolyTraitRef<'tcx>>,
+}
+
+impl<'tcx> Elaborator<'tcx> {
+ fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
+ let supertrait_refs = self
+ .tcx
+ .super_predicates_of(trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .flat_map(|(pred, _)| {
+ pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
+ })
+ .map(|t| t.map_bound(|pred| pred.trait_ref))
+ .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
+
+ self.stack.extend(supertrait_refs);
+ }
+}
+
+impl<'tcx> Iterator for Elaborator<'tcx> {
+ type Item = PolyTraitRef<'tcx>;
+
+ fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
+ if let Some(trait_ref) = self.stack.pop() {
+ self.elaborate(trait_ref);
+ Some(trait_ref)
+ } else {
+ None
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
new file mode 100644
index 000000000..e6aab30a1
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -0,0 +1,124 @@
+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<'tcx> Match<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
+ Match { tcx, param_env }
+ }
+}
+
+impl<'tcx> 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,
+ _: ty::VarianceDiagInfo<'tcx>,
+ a: T,
+ b: T,
+ ) -> RelateResult<'tcx, T> {
+ self.relate(a, b)
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn regions(
+ &mut self,
+ a: ty::Region<'tcx>,
+ b: ty::Region<'tcx>,
+ ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+ Ok(a)
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ 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().ty_error()),
+
+ _ => relate::super_relate_tys(self, a, b),
+ }
+ }
+
+ fn consts(
+ &mut self,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+ debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+ if a == b {
+ return Ok(a);
+ }
+
+ match (a.kind(), b.kind()) {
+ (_, 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<'tcx, T>,
+ b: ty::Binder<'tcx, T>,
+ ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+ where
+ T: Relate<'tcx>,
+ {
+ Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
new file mode 100644
index 000000000..bed809930
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -0,0 +1,194 @@
+//! A subset of a mir body used for const evaluatability checking.
+use crate::mir;
+use crate::ty::visit::TypeVisitable;
+use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def_id::DefId;
+use std::cmp;
+use std::ops::ControlFlow;
+
+rustc_index::newtype_index! {
+ /// An index into an `AbstractConst`.
+ pub struct NodeId {
+ derive [HashStable]
+ DEBUG_FORMAT = "n{}",
+ }
+}
+
+/// A tree representing an anonymous constant.
+///
+/// This is only able to represent a subset of `MIR`,
+/// and should not leak any information about desugarings.
+#[derive(Debug, Clone, Copy)]
+pub struct AbstractConst<'tcx> {
+ // FIXME: Consider adding something like `IndexSlice`
+ // and use this here.
+ inner: &'tcx [Node<'tcx>],
+ substs: SubstsRef<'tcx>,
+}
+
+impl<'tcx> AbstractConst<'tcx> {
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ uv: ty::Unevaluated<'tcx, ()>,
+ ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
+ let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
+ debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
+ Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) }))
+ }
+
+ pub fn from_const(
+ tcx: TyCtxt<'tcx>,
+ ct: ty::Const<'tcx>,
+ ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
+ match ct.kind() {
+ ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
+ ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
+ _ => Ok(None),
+ }
+ }
+
+ #[inline]
+ pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
+ AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
+ }
+
+ #[inline]
+ pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
+ let node = self.inner.last().copied().unwrap();
+ match node {
+ Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)),
+ Node::Cast(kind, operand, ty) => {
+ Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs))
+ }
+ // Don't perform substitution on the following as they can't directly contain generic params
+ Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
+ }
+ }
+
+ pub fn unify_failure_kind(self, tcx: TyCtxt<'tcx>) -> FailureKind {
+ let mut failure_kind = FailureKind::Concrete;
+ walk_abstract_const::<!, _>(tcx, self, |node| {
+ match node.root(tcx) {
+ Node::Leaf(leaf) => {
+ if leaf.has_infer_types_or_consts() {
+ failure_kind = FailureKind::MentionsInfer;
+ } else if leaf.has_param_types_or_consts() {
+ failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+ }
+ }
+ Node::Cast(_, _, ty) => {
+ if ty.has_infer_types_or_consts() {
+ failure_kind = FailureKind::MentionsInfer;
+ } else if ty.has_param_types_or_consts() {
+ failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+ }
+ }
+ Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {}
+ }
+ ControlFlow::CONTINUE
+ });
+ failure_kind
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum CastKind {
+ /// thir::ExprKind::As
+ As,
+ /// thir::ExprKind::Use
+ Use,
+}
+
+/// A node of an `AbstractConst`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum Node<'tcx> {
+ Leaf(ty::Const<'tcx>),
+ Binop(mir::BinOp, NodeId, NodeId),
+ UnaryOp(mir::UnOp, NodeId),
+ FunctionCall(NodeId, &'tcx [NodeId]),
+ Cast(CastKind, NodeId, Ty<'tcx>),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum NotConstEvaluatable {
+ Error(ErrorGuaranteed),
+ MentionsInfer,
+ MentionsParam,
+}
+
+impl From<ErrorGuaranteed> for NotConstEvaluatable {
+ fn from(e: ErrorGuaranteed) -> NotConstEvaluatable {
+ NotConstEvaluatable::Error(e)
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ NotConstEvaluatable,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ #[inline]
+ pub fn thir_abstract_const_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<DefId>,
+ ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> {
+ if let Some((did, param_did)) = def.as_const_arg() {
+ self.thir_abstract_const_of_const_arg((did, param_did))
+ } else {
+ self.thir_abstract_const(def.did)
+ }
+ }
+}
+
+#[instrument(skip(tcx, f), level = "debug")]
+pub fn walk_abstract_const<'tcx, R, F>(
+ tcx: TyCtxt<'tcx>,
+ ct: AbstractConst<'tcx>,
+ mut f: F,
+) -> ControlFlow<R>
+where
+ F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
+{
+ #[instrument(skip(tcx, f), level = "debug")]
+ fn recurse<'tcx, R>(
+ tcx: TyCtxt<'tcx>,
+ ct: AbstractConst<'tcx>,
+ f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
+ ) -> ControlFlow<R> {
+ f(ct)?;
+ let root = ct.root(tcx);
+ debug!(?root);
+ match root {
+ Node::Leaf(_) => ControlFlow::CONTINUE,
+ Node::Binop(_, l, r) => {
+ recurse(tcx, ct.subtree(l), f)?;
+ recurse(tcx, ct.subtree(r), f)
+ }
+ Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f),
+ Node::FunctionCall(func, args) => {
+ recurse(tcx, ct.subtree(func), f)?;
+ args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
+ }
+ Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
+ }
+ }
+
+ recurse(tcx, ct, &mut f)
+}
+
+// We were unable to unify the abstract constant with
+// a constant found in the caller bounds, there are
+// now three possible cases here.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum FailureKind {
+ /// The abstract const still references an inference
+ /// variable, in this case we return `TooGeneric`.
+ MentionsInfer,
+ /// The abstract const references a generic parameter,
+ /// this means that we emit an error here.
+ MentionsParam,
+ /// The substs are concrete enough that we can simply
+ /// try and evaluate the given constant.
+ Concrete,
+}
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
new file mode 100644
index 000000000..d36cf2fe3
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -0,0 +1,198 @@
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_macros::HashStable;
+use rustc_span::Span;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, 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:
+///
+/// ```ignore (illustrative)
+/// 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, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct Adjustment<'tcx> {
+ pub kind: Adjust<'tcx>,
+ pub target: Ty<'tcx>,
+}
+
+impl<'tcx> Adjustment<'tcx> {
+ pub fn is_region_borrow(&self) -> bool {
+ matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
+ }
+}
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+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, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct OverloadedDeref<'tcx> {
+ pub region: ty::Region<'tcx>,
+ pub mutbl: hir::Mutability,
+ /// The `Span` associated with the field access or method call
+ /// that triggered this overloaded deref.
+ pub span: Span,
+}
+
+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.require_lang_item(LangItem::Deref, None),
+ hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
+ };
+ let method_def_id = tcx
+ .associated_items(trait_def_id)
+ .in_definition_order()
+ .find(|m| m.kind == ty::AssocKind::Fn)
+ .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, TyEncodable, TyDecodable, HashStable)]
+pub enum AllowTwoPhase {
+ Yes,
+ No,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, 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, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+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, TyEncodable, TyDecodable, 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, TyEncodable, TyDecodable, Debug, HashStable)]
+pub enum CustomCoerceUnsized {
+ /// Records the index of the field being coerced.
+ Struct(usize),
+}
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
new file mode 100644
index 000000000..2e596b275
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -0,0 +1,569 @@
+use crate::mir::interpret::ErrorHandled;
+use crate::ty;
+use crate::ty::util::{Discr, IntTypeExt};
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::intern::Interned;
+use rustc_data_structures::stable_hasher::HashingControls;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
+use rustc_session::DataTypeKind;
+use rustc_span::symbol::sym;
+use rustc_target::abi::VariantIdx;
+
+use std::cell::RefCell;
+use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
+use std::ops::Range;
+use std::str;
+
+use super::{
+ Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
+};
+
+#[derive(Copy, Clone, HashStable, Debug)]
+pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
+
+bitflags! {
+ #[derive(HashStable, TyEncodable, TyDecodable)]
+ 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;
+ /// 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 << 8;
+ /// Indicates whether the type is `UnsafeCell`.
+ const IS_UNSAFE_CELL = 1 << 9;
+ }
+}
+
+/// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`.
+///
+/// These are all interned (by `alloc_adt_def`) into the global arena.
+///
+/// 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
+///
+/// # Recursive types
+///
+/// It may seem impossible to represent recursive types using [`Ty`],
+/// since [`TyKind::Adt`] includes [`AdtDef`], which includes its fields,
+/// creating a cycle. However, `AdtDef` does not actually include the *types*
+/// of its fields; it includes just their [`DefId`]s.
+///
+/// [`TyKind::Adt`]: ty::TyKind::Adt
+///
+/// For example, the following type:
+///
+/// ```
+/// struct S { x: Box<S> }
+/// ```
+///
+/// is essentially represented with [`Ty`] as the following pseudocode:
+///
+/// ```ignore (illustrative)
+/// struct S { x }
+/// ```
+///
+/// where `x` here represents the `DefId` of `S.x`. Then, the `DefId`
+/// can be used with [`TyCtxt::type_of()`] to get the type of the field.
+#[derive(TyEncodable, TyDecodable)]
+pub struct AdtDefData {
+ /// 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.
+ variants: IndexVec<VariantIdx, VariantDef>,
+ /// Flags of the ADT (e.g., is this a struct? is this non-exhaustive?).
+ flags: AdtFlags,
+ /// Repr options provided by the user.
+ repr: ReprOptions,
+}
+
+impl PartialOrd for AdtDefData {
+ fn partial_cmp(&self, other: &AdtDefData) -> 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 AdtDefData {
+ fn cmp(&self, other: &AdtDefData) -> Ordering {
+ self.did.cmp(&other.did)
+ }
+}
+
+/// There should be only one AdtDef for each `did`, therefore
+/// it is fine to implement `PartialEq` only based on `did`.
+impl PartialEq for AdtDefData {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.did == other.did
+ }
+}
+
+impl Eq for AdtDefData {}
+
+/// There should be only one AdtDef for each `did`, therefore
+/// it is fine to implement `Hash` only based on `did`.
+impl Hash for AdtDefData {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ self.did.hash(s)
+ }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for AdtDefData {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ thread_local! {
+ static CACHE: RefCell<FxHashMap<(usize, HashingControls), Fingerprint>> = Default::default();
+ }
+
+ let hash: Fingerprint = CACHE.with(|cache| {
+ let addr = self as *const AdtDefData as usize;
+ let hashing_controls = hcx.hashing_controls();
+ *cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| {
+ let ty::AdtDefData { 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, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)]
+#[rustc_pass_by_value]
+pub struct AdtDef<'tcx>(pub Interned<'tcx, AdtDefData>);
+
+impl<'tcx> AdtDef<'tcx> {
+ #[inline]
+ pub fn did(self) -> DefId {
+ self.0.0.did
+ }
+
+ #[inline]
+ pub fn variants(self) -> &'tcx IndexVec<VariantIdx, VariantDef> {
+ &self.0.0.variants
+ }
+
+ #[inline]
+ pub fn variant(self, idx: VariantIdx) -> &'tcx VariantDef {
+ &self.0.0.variants[idx]
+ }
+
+ #[inline]
+ pub fn flags(self) -> AdtFlags {
+ self.0.0.flags
+ }
+
+ #[inline]
+ pub fn repr(self) -> ReprOptions {
+ self.0.0.repr
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
+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,
+ }
+ }
+}
+
+impl AdtDefData {
+ /// Creates a new `AdtDefData`.
+ pub(super) 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;
+ }
+
+ if tcx.has_attr(did, 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().unsafe_cell_type() {
+ flags |= AdtFlags::IS_UNSAFE_CELL;
+ }
+
+ AdtDefData { did, variants, flags, repr }
+ }
+}
+
+impl<'tcx> AdtDef<'tcx> {
+ /// 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 an 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 Box<T>.
+ #[inline]
+ pub fn is_box(self) -> bool {
+ self.flags().contains(AdtFlags::IS_BOX)
+ }
+
+ /// Returns `true` if this is UnsafeCell<T>.
+ #[inline]
+ pub fn is_unsafe_cell(self) -> bool {
+ self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
+ }
+
+ /// 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()
+ }
+
+ pub fn has_non_const_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
+ matches!(self.destructor(tcx), Some(Destructor { constness: hir::Constness::NotConst, .. }))
+ }
+
+ /// Asserts this is a struct or union and returns its unique variant.
+ pub fn non_enum_variant(self) -> &'tcx VariantDef {
+ assert!(self.is_struct() || self.is_union());
+ &self.variant(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 = &'tcx FieldDef> + Clone {
+ self.variants().iter().flat_map(|v| v.fields.iter())
+ }
+
+ /// Whether the ADT lacks fields. Note that this includes uninhabited enums,
+ /// e.g., `enum Void {}` is considered payload free as well.
+ pub fn is_payloadfree(self) -> bool {
+ // Treat the ADT as not payload-free if arbitrary_enum_discriminant is used (#88621).
+ // This would disallow the following kind of enum from being casted into integer.
+ // ```
+ // enum Enum {
+ // Foo() = 1,
+ // Bar{} = 2,
+ // Baz = 3,
+ // }
+ // ```
+ if self
+ .variants()
+ .iter()
+ .any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const)
+ {
+ return false;
+ }
+ self.variants().iter().all(|v| v.fields.is_empty())
+ }
+
+ /// Return a `VariantDef` given a variant id.
+ pub fn variant_with_id(self, vid: DefId) -> &'tcx 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) -> &'tcx 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) -> &'tcx 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>> {
+ assert!(self.is_enum());
+ 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(err) => {
+ let msg = match err {
+ ErrorHandled::Reported(_) | ErrorHandled::Linted => {
+ "enum discriminant evaluation failed"
+ }
+ ErrorHandled::TooGeneric => "enum discriminant depends on generics",
+ };
+ tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
+ None
+ }
+ }
+ }
+
+ #[inline]
+ pub fn discriminants(
+ self,
+ tcx: TyCtxt<'tcx>,
+ ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> {
+ assert!(self.is_enum());
+ 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> {
+ assert!(self.is_enum());
+ 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) {
+ assert!(!self.variants().is_empty());
+ let mut explicit_index = variant_index.as_u32();
+ let expr_did;
+ loop {
+ match self.variant(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>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
+ ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
new file mode 100644
index 000000000..c97156ac1
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -0,0 +1,195 @@
+pub use self::AssocItemContainer::*;
+
+use crate::ty::{self, DefIdTree};
+use rustc_data_structures::sorted_map::SortedIndexMultiMap;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::{Ident, Symbol};
+
+use super::{TyCtxt, Visibility};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
+pub enum AssocItemContainer {
+ TraitContainer,
+ ImplContainer,
+}
+
+/// Information about an associated item
+#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
+pub struct AssocItem {
+ pub def_id: DefId,
+ pub name: Symbol,
+ pub kind: AssocKind,
+ pub container: AssocItemContainer,
+
+ /// If this is an item in an impl of a trait then this is the `DefId` of
+ /// the associated item on the trait that this implements.
+ pub trait_item_def_id: Option<DefId>,
+
+ /// Whether this is a method with an explicit self
+ /// as its first parameter, allowing method calls.
+ pub fn_has_self_parameter: bool,
+}
+
+impl AssocItem {
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+ }
+
+ pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
+ tcx.impl_defaultness(self.def_id)
+ }
+
+ #[inline]
+ pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+ tcx.visibility(self.def_id)
+ }
+
+ #[inline]
+ pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
+ tcx.parent(self.def_id)
+ }
+
+ #[inline]
+ pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.container {
+ AssocItemContainer::ImplContainer => None,
+ AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
+ }
+ }
+
+ #[inline]
+ pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.container {
+ AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
+ AssocItemContainer::TraitContainer => None,
+ }
+ }
+
+ pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
+ match self.kind {
+ ty::AssocKind::Fn => {
+ // 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.name),
+ ty::AssocKind::Const => {
+ format!("const {}: {:?};", self.name, tcx.type_of(self.def_id))
+ }
+ }
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
+pub enum AssocKind {
+ Const,
+ Fn,
+ Type,
+}
+
+impl AssocKind {
+ pub fn namespace(&self) -> Namespace {
+ match *self {
+ ty::AssocKind::Type => Namespace::TypeNS,
+ ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
+ }
+ }
+
+ pub fn as_def_kind(&self) -> DefKind {
+ match self {
+ AssocKind::Const => DefKind::AssocConst,
+ AssocKind::Fn => DefKind::AssocFn,
+ AssocKind::Type => DefKind::AssocTy,
+ }
+ }
+}
+
+impl std::fmt::Display for AssocKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AssocKind::Fn => write!(f, "method"),
+ AssocKind::Const => write!(f, "associated const"),
+ AssocKind::Type => write!(f, "associated type"),
+ }
+ }
+}
+
+/// 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 AssocItems<'tcx> {
+ pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
+}
+
+impl<'tcx> AssocItems<'tcx> {
+ /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
+ pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self {
+ let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
+ AssocItems { 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)
+ }
+
+ pub fn len(&self) -> usize {
+ self.items.len()
+ }
+
+ /// 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).copied()
+ }
+
+ /// 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(tcx), parent_def_id))
+ }
+
+ /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
+ pub fn find_by_name_and_kinds(
+ &self,
+ tcx: TyCtxt<'_>,
+ ident: Ident,
+ // Sorted in order of what kinds to look at
+ kinds: &[AssocKind],
+ parent_def_id: DefId,
+ ) -> Option<&ty::AssocItem> {
+ kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, 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(tcx), parent_def_id))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
new file mode 100644
index 000000000..3d65429f2
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -0,0 +1,22 @@
+use rustc_hir::BindingAnnotation;
+use rustc_hir::BindingAnnotation::*;
+use rustc_hir::Mutability;
+
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)]
+pub enum BindingMode {
+ BindByReference(Mutability),
+ BindByValue(Mutability),
+}
+
+TrivialTypeTraversalAndLiftImpls! { 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/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
new file mode 100644
index 000000000..c4b743dd4
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -0,0 +1,73 @@
+// Helpers for handling cast expressions, used in both
+// typeck and codegen.
+
+use crate::ty::{self, Ty};
+
+use rustc_macros::HashStable;
+
+/// Types that are represented as ints.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum IntTy {
+ U(ty::UintTy),
+ I,
+ CEnum,
+ Bool,
+ Char,
+}
+
+impl IntTy {
+ pub fn is_signed(self) -> bool {
+ matches!(self, Self::I)
+ }
+}
+
+// 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](https://rust-lang.github.io/rfcs/0401-coercions.html)
+/// (or librustc_typeck/check/cast.rs).
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, 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/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
new file mode 100644
index 000000000..0d6c26a58
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -0,0 +1,454 @@
+use crate::hir::place::{
+ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
+};
+use crate::{mir, ty};
+
+use std::fmt::Write;
+
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_span::{Span, Symbol};
+
+use super::{Ty, TyCtxt};
+
+use self::BorrowKind::*;
+
+// Captures are represented using fields inside a structure.
+// This represents accessing self in the closure structure
+pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+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, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct UpvarId {
+ pub var_path: UpvarPath,
+ pub closure_expr_id: LocalDefId,
+}
+
+impl UpvarId {
+ pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId {
+ UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id }
+ }
+}
+
+/// Information describing the capture of an upvar. This is computed
+/// during `typeck`, specifically by `regionck`.
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum UpvarCapture {
+ /// 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(BorrowKind),
+}
+
+pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
+pub type UpvarCaptureMap = FxHashMap<UpvarId, UpvarCapture>;
+
+/// Given the closure DefId this map provides a map of root variables to minimum
+/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
+pub type MinCaptureInformationMap<'tcx> = FxHashMap<LocalDefId, RootVariableMinCaptureList<'tcx>>;
+
+/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`.
+/// Used to track the minimum set of `Place`s that need to be captured to support all
+/// Places captured by the closure starting at a given root variable.
+///
+/// This provides a convenient and quick way of checking if a variable being used within
+/// a closure is a capture of a local variable.
+pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
+
+/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
+pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
+
+/// 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, TyEncodable, TyDecodable)]
+#[derive(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;
+
+ /// Returns `true` if a type that impls this closure kind
+ /// must also implement `other`.
+ pub fn extends(self, other: ty::ClosureKind) -> bool {
+ matches!(
+ (self, other),
+ (ClosureKind::Fn, ClosureKind::Fn)
+ | (ClosureKind::Fn, ClosureKind::FnMut)
+ | (ClosureKind::Fn, ClosureKind::FnOnce)
+ | (ClosureKind::FnMut, ClosureKind::FnMut)
+ | (ClosureKind::FnMut, ClosureKind::FnOnce)
+ | (ClosureKind::FnOnce, ClosureKind::FnOnce)
+ )
+ }
+
+ /// Returns the representative scalar type for this closure kind.
+ /// See `Ty::to_opt_closure_kind` for more details.
+ pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ match self {
+ ClosureKind::Fn => tcx.types.i8,
+ ClosureKind::FnMut => tcx.types.i16,
+ ClosureKind::FnOnce => tcx.types.i32,
+ }
+ }
+
+ pub fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ClosureKind> {
+ if Some(def_id) == tcx.lang_items().fn_once_trait() {
+ Some(ClosureKind::FnOnce)
+ } else if Some(def_id) == tcx.lang_items().fn_mut_trait() {
+ Some(ClosureKind::FnMut)
+ } else if Some(def_id) == tcx.lang_items().fn_trait() {
+ Some(ClosureKind::Fn)
+ } else {
+ None
+ }
+ }
+
+ pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
+ match self {
+ ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(),
+ ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(),
+ ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(),
+ }
+ }
+}
+
+/// A composite describing a `Place` that is captured by a closure.
+#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct CapturedPlace<'tcx> {
+ /// The `Place` that is captured.
+ pub place: HirPlace<'tcx>,
+
+ /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
+ pub info: CaptureInfo,
+
+ /// Represents if `place` can be mutated or not.
+ pub mutability: hir::Mutability,
+
+ /// Region of the resulting reference if the upvar is captured by ref.
+ pub region: Option<ty::Region<'tcx>>,
+}
+
+impl<'tcx> CapturedPlace<'tcx> {
+ pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
+ place_to_string_for_capture(tcx, &self.place)
+ }
+
+ /// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
+ fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
+ let hir_id = match self.place.base {
+ HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+ base => bug!("Expected an upvar, found {:?}", base),
+ };
+ let mut symbol = tcx.hir().name(hir_id).as_str().to_string();
+
+ let mut ty = self.place.base_ty;
+ for proj in self.place.projections.iter() {
+ match proj.kind {
+ HirProjectionKind::Field(idx, variant) => match ty.kind() {
+ ty::Tuple(_) => write!(&mut symbol, "__{}", idx).unwrap(),
+ ty::Adt(def, ..) => {
+ write!(
+ &mut symbol,
+ "__{}",
+ def.variant(variant).fields[idx as usize].name.as_str(),
+ )
+ .unwrap();
+ }
+ ty => {
+ span_bug!(
+ self.get_capture_kind_span(tcx),
+ "Unexpected type {:?} for `Field` projection",
+ ty
+ )
+ }
+ },
+
+ // Ignore derefs for now, as they are likely caused by
+ // autoderefs that don't appear in the original code.
+ HirProjectionKind::Deref => {}
+ proj => bug!("Unexpected projection {:?} in captured place", proj),
+ }
+ ty = proj.ty;
+ }
+
+ Symbol::intern(&symbol)
+ }
+
+ /// Returns the hir-id of the root variable for the captured place.
+ /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
+ pub fn get_root_variable(&self) -> hir::HirId {
+ match self.place.base {
+ HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+ base => bug!("Expected upvar, found={:?}", base),
+ }
+ }
+
+ /// Returns the `LocalDefId` of the closure that captured this Place
+ pub fn get_closure_local_def_id(&self) -> LocalDefId {
+ match self.place.base {
+ HirPlaceBase::Upvar(upvar_id) => upvar_id.closure_expr_id,
+ base => bug!("expected upvar, found={:?}", base),
+ }
+ }
+
+ /// Return span pointing to use that resulted in selecting the captured path
+ pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
+ if let Some(path_expr_id) = self.info.path_expr_id {
+ tcx.hir().span(path_expr_id)
+ } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
+ tcx.hir().span(capture_kind_expr_id)
+ } else {
+ // Fallback on upvars mentioned if neither path or capture expr id is captured
+
+ // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
+ tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
+ [&self.get_root_variable()]
+ .span
+ }
+ }
+
+ /// Return span pointing to use that resulted in selecting the current capture kind
+ pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
+ if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
+ tcx.hir().span(capture_kind_expr_id)
+ } else if let Some(path_expr_id) = self.info.path_expr_id {
+ tcx.hir().span(path_expr_id)
+ } else {
+ // Fallback on upvars mentioned if neither path or capture expr id is captured
+
+ // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
+ tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
+ [&self.get_root_variable()]
+ .span
+ }
+ }
+}
+
+fn symbols_for_closure_captures<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: (LocalDefId, LocalDefId),
+) -> Vec<Symbol> {
+ let typeck_results = tcx.typeck(def_id.0);
+ let captures = typeck_results.closure_min_captures_flattened(def_id.1);
+ captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect()
+}
+
+/// Return true if the `proj_possible_ancestor` represents an ancestor path
+/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
+/// assuming they both start off of the same root variable.
+///
+/// **Note:** It's the caller's responsibility to ensure that both lists of projections
+/// start off of the same root variable.
+///
+/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
+/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
+/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
+/// 2. Since we only look at the projections here function will return `bar.x` as an a valid
+/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
+/// list are being applied to the same root variable.
+pub fn is_ancestor_or_same_capture(
+ proj_possible_ancestor: &[HirProjectionKind],
+ proj_capture: &[HirProjectionKind],
+) -> bool {
+ // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
+ // Therefore we can't just check if all projections are same in the zipped iterator below.
+ if proj_possible_ancestor.len() > proj_capture.len() {
+ return false;
+ }
+
+ proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b)
+}
+
+/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
+/// for a particular capture as well as identifying the part of the source code
+/// that triggered this capture to occur.
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct CaptureInfo {
+ /// Expr Id pointing to use that resulted in selecting the current capture kind
+ ///
+ /// Eg:
+ /// ```rust,no_run
+ /// let mut t = (0,1);
+ ///
+ /// let c = || {
+ /// println!("{t:?}"); // L1
+ /// t.1 = 4; // L2
+ /// };
+ /// ```
+ /// `capture_kind_expr_id` will point to the use on L2 and `path_expr_id` will point to the
+ /// use on L1.
+ ///
+ /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
+ /// possible that we don't see the use of a particular place resulting in capture_kind_expr_id being
+ /// None. In such case we fallback on uvpars_mentioned for span.
+ ///
+ /// Eg:
+ /// ```rust,no_run
+ /// let x = 5;
+ ///
+ /// let c = || {
+ /// let _ = x;
+ /// };
+ /// ```
+ ///
+ /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
+ /// but we won't see it being used during capture analysis, since it's essentially a discard.
+ pub capture_kind_expr_id: Option<hir::HirId>,
+ /// Expr Id pointing to use that resulted the corresponding place being captured
+ ///
+ /// See `capture_kind_expr_id` for example.
+ ///
+ pub path_expr_id: Option<hir::HirId>,
+
+ /// Capture mode that was selected
+ pub capture_kind: UpvarCapture,
+}
+
+pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
+ let mut curr_string: String = match place.base {
+ HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
+ _ => bug!("Capture_information should only contain upvars"),
+ };
+
+ for (i, proj) in place.projections.iter().enumerate() {
+ match proj.kind {
+ HirProjectionKind::Deref => {
+ curr_string = format!("*{}", curr_string);
+ }
+ HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
+ ty::Adt(def, ..) => {
+ curr_string = format!(
+ "{}.{}",
+ curr_string,
+ def.variant(variant).fields[idx as usize].name.as_str()
+ );
+ }
+ ty::Tuple(_) => {
+ curr_string = format!("{}.{}", curr_string, idx);
+ }
+ _ => {
+ bug!(
+ "Field projection applied to a type other than Adt or Tuple: {:?}.",
+ place.ty_before_projection(i).kind()
+ )
+ }
+ },
+ proj => bug!("{:?} unexpected because it isn't captured", proj),
+ }
+ }
+
+ curr_string
+}
+
+#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+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 mut z = 3;
+ /// let x: &mut isize = &mut z;
+ /// 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:
+ ///
+ /// ```compile_fail,E0594
+ /// struct Env<'a> { x: &'a &'a mut isize }
+ /// let mut z = 3;
+ /// let x: &mut isize = &mut z;
+ /// let y = (&mut Env { x: &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:
+ ///
+ /// ```compile_fail,E0596
+ /// struct Env<'a> { x: &'a mut &'a mut isize }
+ /// let mut z = 3;
+ /// let x: &mut isize = &mut z;
+ /// let y = (&mut Env { x: &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,
+}
+
+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 a `&uniq`
+ // and hence is a safe "over approximation".
+ UniqueImmBorrow => hir::Mutability::Mut,
+ }
+ }
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { symbols_for_closure_captures, ..*providers }
+}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
new file mode 100644
index 000000000..51137c526
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -0,0 +1,527 @@
+//! 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::{AllocId, ConstAllocation},
+};
+use crate::traits;
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, AdtDef, Ty};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::TyCtxt;
+use rustc_serialize::{Decodable, Encodable};
+use rustc_span::Span;
+pub use rustc_type_ir::{TyDecoder, TyEncoder};
+use std::hash::Hash;
+use std::intrinsics;
+use std::marker::DiscriminantKind;
+
+/// 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<E: TyEncoder>: Copy + Eq + Hash {
+ type Variant: Encodable<E>;
+ fn variant(&self) -> &Self::Variant;
+}
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> EncodableWithShorthand<E> for Ty<'tcx> {
+ type Variant = ty::TyKind<'tcx>;
+
+ #[inline]
+ fn variant(&self) -> &Self::Variant {
+ self.kind()
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> EncodableWithShorthand<E> for ty::PredicateKind<'tcx> {
+ type Variant = ty::PredicateKind<'tcx>;
+
+ #[inline]
+ fn variant(&self) -> &Self::Variant {
+ self
+ }
+}
+
+/// Trait for decoding to a reference.
+///
+/// This is a separate trait from `Decodable` so that we can implement it for
+/// upstream types, such as `FxHashSet`.
+///
+/// The `TyDecodable` derive macro will use this trait for fields that are
+/// references (and don't use a type alias to hide that).
+///
+/// `Decodable` can still be implemented in cases where `Decodable` is required
+/// by a trait bound.
+pub trait RefDecodable<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> {
+ fn decode(d: &mut D) -> &'tcx Self;
+}
+
+/// Encode the given value or a previously cached shorthand.
+pub fn encode_with_shorthand<'tcx, E, T, M>(encoder: &mut E, value: &T, cache: M)
+where
+ E: TyEncoder<I = TyCtxt<'tcx>>,
+ M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
+ T: EncodableWithShorthand<E>,
+ // The discriminant and shorthand must have the same size.
+ T::Variant: DiscriminantKind<Discriminant = isize>,
+{
+ let existing_shorthand = cache(encoder).get(value).copied();
+ if let Some(shorthand) = existing_shorthand {
+ encoder.emit_usize(shorthand);
+ return;
+ }
+
+ 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!(SHORTHAND_OFFSET > discriminant as usize);
+
+ 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, shorthand);
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Ty<'tcx> {
+ fn encode(&self, e: &mut E) {
+ encode_with_shorthand(e, self, TyEncoder::type_shorthands);
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E>
+ for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
+{
+ fn encode(&self, e: &mut E) {
+ self.bound_vars().encode(e);
+ encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands);
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.kind().encode(e);
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Region<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.kind().encode(e);
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.0.0.encode(e);
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.inner().encode(e)
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AdtDef<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.0.0.encode(e)
+ }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId {
+ fn encode(&self, e: &mut E) {
+ e.encode_alloc_id(self)
+ }
+}
+
+#[inline]
+fn decode_arena_allocable<
+ 'tcx,
+ D: TyDecoder<I = TyCtxt<'tcx>>,
+ T: ArenaAllocatable<'tcx> + Decodable<D>,
+>(
+ decoder: &mut D,
+) -> &'tcx T
+where
+ D: TyDecoder,
+{
+ decoder.interner().arena.alloc(Decodable::decode(decoder))
+}
+
+#[inline]
+fn decode_arena_allocable_slice<
+ 'tcx,
+ D: TyDecoder<I = TyCtxt<'tcx>>,
+ T: ArenaAllocatable<'tcx> + Decodable<D>,
+>(
+ decoder: &mut D,
+) -> &'tcx [T]
+where
+ D: TyDecoder,
+{
+ decoder.interner().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> {
+ #[allow(rustc::usage_of_ty_tykind)]
+ fn decode(decoder: &mut D) -> Ty<'tcx> {
+ // Handle shorthands first, if we have a 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.interner();
+ tcx.mk_ty(rustc_type_ir::TyKind::decode(decoder))
+ }
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
+ for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
+{
+ fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+ let bound_vars = Decodable::decode(decoder);
+ // Handle shorthands first, if we have a usize > 0x80.
+ ty::Binder::bind_with_vars(
+ if decoder.positioned_at_shorthand() {
+ let pos = decoder.read_usize();
+ assert!(pos >= SHORTHAND_OFFSET);
+ let shorthand = pos - SHORTHAND_OFFSET;
+
+ decoder.with_position(shorthand, ty::PredicateKind::decode)
+ } else {
+ ty::PredicateKind::decode(decoder)
+ },
+ bound_vars,
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
+ fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
+ let predicate_kind = Decodable::decode(decoder);
+ decoder.interner().mk_predicate(predicate_kind)
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ let len = decoder.read_usize();
+ let tcx = decoder.interner();
+ tcx.mk_substs(
+ (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)),
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ let local: mir::Local = Decodable::decode(decoder);
+ let len = decoder.read_usize();
+ let projection = decoder.interner().mk_place_elems(
+ (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)),
+ );
+ mir::Place { local, projection }
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Region<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ decoder.interner().mk_region(Decodable::decode(decoder))
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CanonicalVarInfos<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ let len = decoder.read_usize();
+ let interned: Vec<CanonicalVarInfo<'tcx>> =
+ (0..len).map(|_| Decodable::decode(decoder)).collect();
+ decoder.interner().intern_canonical_var_infos(interned.as_slice())
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId {
+ fn decode(decoder: &mut D) -> Self {
+ decoder.decode_alloc_id()
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ ty::SymbolName::new(decoder.interner(), &decoder.read_str())
+ }
+}
+
+macro_rules! impl_decodable_via_ref {
+ ($($t:ty),+) => {
+ $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for $t {
+ fn decode(decoder: &mut D) -> Self {
+ RefDecodable::decode(decoder)
+ }
+ })*
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.interner().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+ for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
+{
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.interner().mk_poly_existential_predicates(
+ (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)),
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ decoder.interner().mk_const(Decodable::decode(decoder))
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.interner().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ConstAllocation<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ decoder.interner().intern_const_alloc(Decodable::decode(decoder))
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
+ decoder.interner().intern_adt_def(Decodable::decode(decoder))
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+ for [(ty::Predicate<'tcx>, Span)]
+{
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.interner().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+ for [ty::abstract_const::Node<'tcx>]
+{
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.interner().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+ for [ty::abstract_const::NodeId]
+{
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.interner().arena.alloc_from_iter(
+ (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+ )
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+ for ty::List<ty::BoundVariableKind>
+{
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.interner().mk_bound_variable_kinds(
+ (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
+ )
+ }
+}
+
+impl_decodable_via_ref! {
+ &'tcx ty::TypeckResults<'tcx>,
+ &'tcx ty::List<Ty<'tcx>>,
+ &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ &'tcx traits::ImplSource<'tcx, ()>,
+ &'tcx mir::Body<'tcx>,
+ &'tcx mir::UnsafetyCheckResult,
+ &'tcx mir::BorrowCheckResult<'tcx>,
+ &'tcx mir::coverage::CodeRegion,
+ &'tcx ty::List<ty::BoundVariableKind>
+}
+
+#[macro_export]
+macro_rules! __impl_decoder_methods {
+ ($($name:ident -> $ty:ty;)*) => {
+ $(
+ #[inline]
+ fn $name(&mut self) -> $ty {
+ self.opaque.$name()
+ }
+ )*
+ }
+}
+
+macro_rules! impl_arena_allocatable_decoder {
+ ([]$args:tt) => {};
+ ([decode $(, $attrs:ident)*]
+ [$name:ident: $ty:ty]) => {
+ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for $ty {
+ #[inline]
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decode_arena_allocable(decoder)
+ }
+ }
+
+ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [$ty] {
+ #[inline]
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decode_arena_allocable_slice(decoder)
+ }
+ }
+ };
+}
+
+macro_rules! impl_arena_allocatable_decoders {
+ ([$($a:tt $name:ident: $ty:ty,)*]) => {
+ $(
+ impl_arena_allocatable_decoder!($a [$name: $ty]);
+ )*
+ }
+}
+
+rustc_hir::arena_types!(impl_arena_allocatable_decoders);
+arena_types!(impl_arena_allocatable_decoders);
+
+macro_rules! impl_arena_copy_decoder {
+ (<$tcx:tt> $($ty:ty,)*) => {
+ $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for $ty {
+ #[inline]
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.interner().arena.alloc(Decodable::decode(decoder))
+ }
+ }
+
+ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [$ty] {
+ #[inline]
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder.interner().arena.alloc_from_iter(<Vec<_> as Decodable<D>>::decode(decoder))
+ }
+ })*
+ };
+}
+
+impl_arena_copy_decoder! {<'tcx>
+ Span,
+ rustc_span::symbol::Ident,
+ ty::Variance,
+ rustc_span::def_id::DefId,
+ rustc_span::def_id::LocalDefId,
+ (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+}
+
+#[macro_export]
+macro_rules! implement_ty_decoder {
+ ($DecoderName:ident <$($typaram:tt),*>) => {
+ mod __ty_decoder_impl {
+ use std::borrow::Cow;
+ use rustc_serialize::Decoder;
+
+ use super::$DecoderName;
+
+ impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
+ $crate::__impl_decoder_methods! {
+ 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 -> &str;
+ }
+
+ #[inline]
+ fn read_raw_bytes(&mut self, len: usize) -> &[u8] {
+ self.opaque.read_raw_bytes(len)
+ }
+ }
+ }
+ }
+}
+
+macro_rules! impl_binder_encode_decode {
+ ($($t:ty),+ $(,)?) => {
+ $(
+ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Binder<'tcx, $t> {
+ fn encode(&self, e: &mut E) {
+ self.bound_vars().encode(e);
+ self.as_ref().skip_binder().encode(e);
+ }
+ }
+ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Binder<'tcx, $t> {
+ fn decode(decoder: &mut D) -> Self {
+ let bound_vars = Decodable::decode(decoder);
+ ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
+ }
+ }
+ )*
+ }
+}
+
+impl_binder_encode_decode! {
+ &'tcx ty::List<Ty<'tcx>>,
+ ty::FnSig<'tcx>,
+ ty::ExistentialPredicate<'tcx>,
+ ty::TraitRef<'tcx>,
+ Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
+ ty::ExistentialTraitRef<'tcx>,
+}
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
new file mode 100644
index 000000000..f8792edc0
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -0,0 +1,326 @@
+use crate::mir::interpret::LitToConstInput;
+use crate::mir::ConstantKind;
+use crate::ty::{
+ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+ TyCtxt, TypeVisitable,
+};
+use rustc_data_structures::intern::Interned;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_macros::HashStable;
+use std::fmt;
+
+mod int;
+mod kind;
+mod valtree;
+
+pub use int::*;
+pub use kind::*;
+pub use valtree::*;
+
+/// Use this rather than `ConstS`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[rustc_pass_by_value]
+pub struct Const<'tcx>(pub Interned<'tcx, ConstS<'tcx>>);
+
+impl<'tcx> fmt::Debug for Const<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This reflects what `Const` looked liked before `Interned` was
+ // introduced. We print it like this to avoid having to update expected
+ // output in a lot of tests.
+ write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
+ }
+}
+
+/// Typed constant value.
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
+pub struct ConstS<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub kind: ConstKind<'tcx>,
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ConstS<'_>, 48);
+
+impl<'tcx> Const<'tcx> {
+ #[inline]
+ pub fn ty(self) -> Ty<'tcx> {
+ self.0.ty
+ }
+
+ #[inline]
+ pub fn kind(self) -> ConstKind<'tcx> {
+ self.0.kind
+ }
+
+ /// Literals and const generic parameters are eagerly converted to a constant, everything else
+ /// becomes `Unevaluated`.
+ pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+ Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
+
+ #[instrument(skip(tcx), level = "debug")]
+ pub fn from_opt_const_arg_anon_const(
+ tcx: TyCtxt<'tcx>,
+ def: ty::WithOptConstParam<LocalDefId>,
+ ) -> Self {
+ debug!("Const::from_anon_const(def={:?})", def);
+
+ let body_id = match tcx.hir().get_by_def_id(def.did) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def.did.to_def_id()),
+ "from_anon_const can only process anonymous constants"
+ ),
+ };
+
+ let expr = &tcx.hir().body(body_id).value;
+ debug!(?expr);
+
+ let ty = tcx.type_of(def.def_id_for_type_of());
+
+ match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: def.to_global(),
+ substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+ promoted: None,
+ }),
+ ty,
+ }),
+ }
+ }
+
+ #[instrument(skip(tcx), level = "debug")]
+ fn try_eval_lit_or_param(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Option<Self> {
+ // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+ // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+ let expr = match &expr.kind {
+ hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+ block.expr.as_ref().unwrap()
+ }
+ _ => expr,
+ };
+
+ let lit_input = match expr.kind {
+ hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+ hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
+ hir::ExprKind::Lit(ref lit) => {
+ Some(LitToConstInput { lit: &lit.node, ty, neg: true })
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+
+ if let Some(lit_input) = lit_input {
+ // If an error occurred, ignore that it's a literal and leave reporting the error up to
+ // mir.
+ match tcx.at(expr.span).lit_to_const(lit_input) {
+ Ok(c) => return Some(c),
+ Err(e) => {
+ tcx.sess.delay_span_bug(
+ expr.span,
+ &format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+ );
+ }
+ }
+ }
+
+ use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
+ match expr.kind {
+ ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
+ // Find the name and index of the const parameter by indexing the generics of
+ // the parent item and construct a `ParamConst`.
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let item_id = tcx.hir().get_parent_node(hir_id);
+ let item_def_id = tcx.hir().local_def_id(item_id);
+ let generics = tcx.generics_of(item_def_id.to_def_id());
+ let index = generics.param_def_id_to_index[&def_id];
+ let name = tcx.hir().name(hir_id);
+ Some(tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+ ty,
+ }))
+ }
+ _ => None,
+ }
+ }
+
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+ debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ let body_id = match tcx.hir().get(hir_id) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def_id.to_def_id()),
+ "from_inline_const can only process anonymous constants"
+ ),
+ };
+
+ let expr = &tcx.hir().body(body_id).value;
+
+ let ty = tcx.typeck(def_id).node_type(hir_id);
+
+ let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+ tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: ty::WithOptConstParam::unknown(def_id).to_global(),
+ substs,
+ promoted: None,
+ }),
+ ty,
+ })
+ }
+ };
+ debug_assert!(!ret.has_free_regions());
+ ret
+ }
+
+ /// Interns the given value as a constant.
+ #[inline]
+ pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self {
+ tcx.mk_const(ConstS { kind: ConstKind::Value(val), ty })
+ }
+
+ /// Panics if self.kind != ty::ConstKind::Value
+ pub fn to_valtree(self) -> ty::ValTree<'tcx> {
+ match self.kind() {
+ ty::ConstKind::Value(valtree) => valtree,
+ _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
+ }
+ }
+
+ pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt, ty: Ty<'tcx>) -> Self {
+ let valtree = ty::ValTree::from_scalar_int(i);
+ Self::from_value(tcx, valtree, ty)
+ }
+
+ #[inline]
+ /// Creates a constant with the given integer value and interns it.
+ pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
+ let size = tcx
+ .layout_of(ty)
+ .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+ .size;
+ Self::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap(), ty.value)
+ }
+
+ #[inline]
+ /// Creates an interned zst constant.
+ pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
+ let valtree = ty::ValTree::zst();
+ Self::from_value(tcx, valtree, ty)
+ }
+
+ #[inline]
+ /// Creates an interned bool constant.
+ pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
+ Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
+ }
+
+ #[inline]
+ /// Creates an interned usize constant.
+ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
+ Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
+ }
+
+ #[inline]
+ /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
+ /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
+ /// contains const generic parameters or pointers).
+ 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_normalized(tcx).and(ty)).ok()?.size;
+ // if `ty` does not depend on generic parameters, use an empty param_env
+ self.kind().eval(tcx, param_env).try_to_bits(size)
+ }
+
+ #[inline]
+ pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+ self.kind().eval(tcx, param_env).try_to_bool()
+ }
+
+ #[inline]
+ pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
+ self.kind().eval(tcx, param_env).try_to_machine_usize(tcx)
+ }
+
+ #[inline]
+ /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
+ /// unevaluated constant.
+ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
+ if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
+ match val {
+ Ok(val) => Const::from_value(tcx, val, self.ty()),
+ Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()),
+ }
+ } else {
+ // Either the constant isn't evaluatable or ValTree creation failed.
+ self
+ }
+ }
+
+ #[inline]
+ /// Tries to evaluate the constant if it is `Unevaluated` and creates a ConstValue if the
+ /// evaluation succeeds. If it doesn't succeed, returns the unevaluated constant.
+ pub fn eval_for_mir(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> ConstantKind<'tcx> {
+ if let Some(val) = self.kind().try_eval_for_mir(tcx, param_env) {
+ match val {
+ Ok(const_val) => ConstantKind::from_value(const_val, self.ty()),
+ Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())),
+ }
+ } else {
+ ConstantKind::Ty(self)
+ }
+ }
+
+ #[inline]
+ /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+ 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]
+ /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
+ pub fn eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
+ self.try_eval_usize(tcx, param_env)
+ .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
+ }
+}
+
+pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
+ let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
+ hir::Node::GenericParam(hir::GenericParam {
+ kind: hir::GenericParamKind::Const { ty: _, default: Some(ac) },
+ ..
+ }) => tcx.hir().local_def_id(ac.hir_id),
+ _ => span_bug!(
+ tcx.def_span(def_id),
+ "`const_param_default` expected a generic parameter with a constant"
+ ),
+ };
+ Const::from_anon_const(tcx, default_def_id)
+}
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
new file mode 100644
index 000000000..7436f0f6f
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -0,0 +1,483 @@
+use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::Float;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use rustc_target::abi::Size;
+use std::convert::{TryFrom, TryInto};
+use std::fmt;
+use std::num::NonZeroU8;
+
+use crate::ty::TyCtxt;
+
+#[derive(Copy, Clone)]
+/// A type for representing any integer. Only used for printing.
+pub struct ConstInt {
+ /// The "untyped" variant of `ConstInt`.
+ int: ScalarInt,
+ /// Whether the value is of a signed integer type.
+ signed: bool,
+ /// Whether the value is a `usize` or `isize` type.
+ is_ptr_sized_integral: bool,
+}
+
+impl ConstInt {
+ pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
+ Self { int, signed, is_ptr_sized_integral }
+ }
+}
+
+impl std::fmt::Debug for ConstInt {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let Self { int, signed, is_ptr_sized_integral } = *self;
+ let size = int.size().bytes();
+ let raw = int.data;
+ if signed {
+ let bit_size = size * 8;
+ let min = 1u128 << (bit_size - 1);
+ let max = min - 1;
+ if raw == min {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "isize::MIN"),
+ (1, _) => write!(fmt, "i8::MIN"),
+ (2, _) => write!(fmt, "i16::MIN"),
+ (4, _) => write!(fmt, "i32::MIN"),
+ (8, _) => write!(fmt, "i64::MIN"),
+ (16, _) => write!(fmt, "i128::MIN"),
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ } else if raw == max {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "isize::MAX"),
+ (1, _) => write!(fmt, "i8::MAX"),
+ (2, _) => write!(fmt, "i16::MAX"),
+ (4, _) => write!(fmt, "i32::MAX"),
+ (8, _) => write!(fmt, "i64::MAX"),
+ (16, _) => write!(fmt, "i128::MAX"),
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ } else {
+ match size {
+ 1 => write!(fmt, "{}", raw as i8)?,
+ 2 => write!(fmt, "{}", raw as i16)?,
+ 4 => write!(fmt, "{}", raw as i32)?,
+ 8 => write!(fmt, "{}", raw as i64)?,
+ 16 => write!(fmt, "{}", raw as i128)?,
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ if fmt.alternate() {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "_isize")?,
+ (1, _) => write!(fmt, "_i8")?,
+ (2, _) => write!(fmt, "_i16")?,
+ (4, _) => write!(fmt, "_i32")?,
+ (8, _) => write!(fmt, "_i64")?,
+ (16, _) => write!(fmt, "_i128")?,
+ _ => bug!(),
+ }
+ }
+ Ok(())
+ }
+ } else {
+ let max = Size::from_bytes(size).truncate(u128::MAX);
+ if raw == max {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "usize::MAX"),
+ (1, _) => write!(fmt, "u8::MAX"),
+ (2, _) => write!(fmt, "u16::MAX"),
+ (4, _) => write!(fmt, "u32::MAX"),
+ (8, _) => write!(fmt, "u64::MAX"),
+ (16, _) => write!(fmt, "u128::MAX"),
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ } else {
+ match size {
+ 1 => write!(fmt, "{}", raw as u8)?,
+ 2 => write!(fmt, "{}", raw as u16)?,
+ 4 => write!(fmt, "{}", raw as u32)?,
+ 8 => write!(fmt, "{}", raw as u64)?,
+ 16 => write!(fmt, "{}", raw as u128)?,
+ _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+ }
+ if fmt.alternate() {
+ match (size, is_ptr_sized_integral) {
+ (_, true) => write!(fmt, "_usize")?,
+ (1, _) => write!(fmt, "_u8")?,
+ (2, _) => write!(fmt, "_u16")?,
+ (4, _) => write!(fmt, "_u32")?,
+ (8, _) => write!(fmt, "_u64")?,
+ (16, _) => write!(fmt, "_u128")?,
+ _ => bug!(),
+ }
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+/// The raw bytes of a simple value.
+///
+/// This is a packed struct in order to allow this type to be optimally embedded in enums
+/// (like Scalar).
+#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[repr(packed)]
+pub struct ScalarInt {
+ /// 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: NonZeroU8,
+}
+
+// Cannot derive these, as the derives take references to the fields, and we
+// can't take references to fields of packed structs.
+impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
+ // Using a block `{self.data}` here to force a copy instead of using `self.data`
+ // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
+ // Since `Self` is a packed struct, that would create a possibly unaligned reference,
+ // which is UB.
+ { self.data }.hash_stable(hcx, hasher);
+ self.size.get().hash_stable(hcx, hasher);
+ }
+}
+
+impl<S: Encoder> Encodable<S> for ScalarInt {
+ fn encode(&self, s: &mut S) {
+ s.emit_u128(self.data);
+ s.emit_u8(self.size.get());
+ }
+}
+
+impl<D: Decoder> Decodable<D> for ScalarInt {
+ fn decode(d: &mut D) -> ScalarInt {
+ ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() }
+ }
+}
+
+impl ScalarInt {
+ pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() };
+
+ pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() };
+
+ #[inline]
+ pub fn size(self) -> Size {
+ Size::from_bytes(self.size.get())
+ }
+
+ /// Make sure the `data` fits in `size`.
+ /// This is guaranteed by all constructors here, but having had this check saved us from
+ /// bugs many times in the past, so keeping it around is definitely worth it.
+ #[inline(always)]
+ fn check_data(self) {
+ // Using a block `{self.data}` here to force a copy instead of using `self.data`
+ // directly, because `debug_assert_eq` takes references to its arguments and formatting
+ // arguments and would thus borrow `self.data`. Since `Self`
+ // is a packed struct, that would create a possibly unaligned reference, which
+ // is UB.
+ debug_assert_eq!(
+ self.size().truncate(self.data),
+ { self.data },
+ "Scalar value {:#x} exceeds size of {} bytes",
+ { self.data },
+ self.size
+ );
+ }
+
+ #[inline]
+ pub fn null(size: Size) -> Self {
+ Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() }
+ }
+
+ #[inline]
+ pub fn is_null(self) -> bool {
+ self.data == 0
+ }
+
+ #[inline]
+ pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
+ let data = i.into();
+ if size.truncate(data) == data {
+ Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
+ } else {
+ None
+ }
+ }
+
+ #[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 = size.truncate(i as u128);
+ if size.sign_extend(truncated) as i128 == i {
+ Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn assert_bits(self, target_size: Size) -> u128 {
+ self.to_bits(target_size).unwrap_or_else(|size| {
+ bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
+ })
+ }
+
+ #[inline]
+ pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
+ assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
+ if target_size.bytes() == u64::from(self.size.get()) {
+ self.check_data();
+ Ok(self.data)
+ } else {
+ Err(self.size())
+ }
+ }
+
+ #[inline]
+ pub fn try_to_machine_usize<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Result<u64, Size> {
+ Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
+ }
+
+ /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
+ /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
+ /// `ScalarInt`s size in that case.
+ #[inline]
+ pub fn try_to_uint(self, size: Size) -> Result<u128, Size> {
+ self.to_bits(size)
+ }
+
+ // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
+ // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
+ // that case.
+ #[inline]
+ pub fn try_to_u8(self) -> Result<u8, Size> {
+ self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
+ /// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
+ /// that case.
+ #[inline]
+ pub fn try_to_u16(self) -> Result<u16, Size> {
+ self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
+ /// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
+ /// that case.
+ #[inline]
+ pub fn try_to_u32(self) -> Result<u32, Size> {
+ self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
+ /// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
+ /// that case.
+ #[inline]
+ pub fn try_to_u64(self) -> Result<u64, Size> {
+ self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
+ /// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
+ /// that case.
+ #[inline]
+ pub fn try_to_u128(self) -> Result<u128, Size> {
+ self.to_bits(Size::from_bits(128))
+ }
+
+ /// Tries to convert the `ScalarInt` to a signed integer of the given size.
+ /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
+ /// `ScalarInt`s size in that case.
+ #[inline]
+ pub fn try_to_int(self, size: Size) -> Result<i128, Size> {
+ let b = self.to_bits(size)?;
+ Ok(size.sign_extend(b) as i128)
+ }
+
+ /// Tries to convert the `ScalarInt` to i8.
+ /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }`
+ /// and returns the `ScalarInt`s size in that case.
+ pub fn try_to_i8(self) -> Result<i8, Size> {
+ self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to i16.
+ /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }`
+ /// and returns the `ScalarInt`s size in that case.
+ pub fn try_to_i16(self) -> Result<i16, Size> {
+ self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to i32.
+ /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }`
+ /// and returns the `ScalarInt`s size in that case.
+ pub fn try_to_i32(self) -> Result<i32, Size> {
+ self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to i64.
+ /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }`
+ /// and returns the `ScalarInt`s size in that case.
+ pub fn try_to_i64(self) -> Result<i64, Size> {
+ self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
+ }
+
+ /// Tries to convert the `ScalarInt` to i128.
+ /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }`
+ /// and returns the `ScalarInt`s size in that case.
+ pub fn try_to_i128(self) -> Result<i128, Size> {
+ self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap())
+ }
+}
+
+macro_rules! from {
+ ($($ty:ty),*) => {
+ $(
+ impl From<$ty> for ScalarInt {
+ #[inline]
+ fn from(u: $ty) -> Self {
+ Self {
+ data: u128::from(u),
+ size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(),
+ }
+ }
+ }
+ )*
+ }
+}
+
+macro_rules! try_from {
+ ($($ty:ty),*) => {
+ $(
+ impl TryFrom<ScalarInt> for $ty {
+ type Error = Size;
+ #[inline]
+ fn try_from(int: ScalarInt) -> Result<Self, Size> {
+ // The `unwrap` cannot fail because to_bits (if it succeeds)
+ // is guaranteed to return a value that fits into the size.
+ int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>()))
+ .map(|u| u.try_into().unwrap())
+ }
+ }
+ )*
+ }
+}
+
+from!(u8, u16, u32, u64, u128, bool);
+try_from!(u8, u16, u32, u64, u128);
+
+impl TryFrom<ScalarInt> for bool {
+ type Error = Size;
+ #[inline]
+ fn try_from(int: ScalarInt) -> Result<Self, Size> {
+ int.to_bits(Size::from_bytes(1)).and_then(|u| match u {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ _ => Err(Size::from_bytes(1)),
+ })
+ }
+}
+
+impl From<char> for ScalarInt {
+ #[inline]
+ fn from(c: char) -> Self {
+ Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() }
+ }
+}
+
+/// Error returned when a conversion from ScalarInt to char fails.
+#[derive(Debug)]
+pub struct CharTryFromScalarInt;
+
+impl TryFrom<ScalarInt> for char {
+ type Error = CharTryFromScalarInt;
+
+ #[inline]
+ fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
+ let Ok(bits) = int.to_bits(Size::from_bytes(std::mem::size_of::<char>())) else {
+ return Err(CharTryFromScalarInt);
+ };
+ match char::from_u32(bits.try_into().unwrap()) {
+ Some(c) => Ok(c),
+ None => Err(CharTryFromScalarInt),
+ }
+ }
+}
+
+impl From<Single> for ScalarInt {
+ #[inline]
+ fn from(f: Single) -> Self {
+ // We trust apfloat to give us properly truncated data.
+ Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() }
+ }
+}
+
+impl TryFrom<ScalarInt> for Single {
+ type Error = Size;
+ #[inline]
+ fn try_from(int: ScalarInt) -> Result<Self, Size> {
+ int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
+ }
+}
+
+impl From<Double> for ScalarInt {
+ #[inline]
+ fn from(f: Double) -> Self {
+ // We trust apfloat to give us properly truncated data.
+ Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() }
+ }
+}
+
+impl TryFrom<ScalarInt> for Double {
+ type Error = Size;
+ #[inline]
+ fn try_from(int: ScalarInt) -> Result<Self, Size> {
+ int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
+ }
+}
+
+impl fmt::Debug for ScalarInt {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Dispatch to LowerHex below.
+ write!(f, "0x{:x}", self)
+ }
+}
+
+impl fmt::LowerHex for ScalarInt {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.check_data();
+ if f.alternate() {
+ // Like regular ints, alternate flag adds leading `0x`.
+ write!(f, "0x")?;
+ }
+ // 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".
+ // Using a block `{self.data}` here to force a copy instead of using `self.data`
+ // directly, because `write!` takes references to its formatting arguments and
+ // would thus borrow `self.data`. Since `Self`
+ // is a packed struct, that would create a possibly unaligned reference, which
+ // is UB.
+ write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
+ }
+}
+
+impl fmt::UpperHex for ScalarInt {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.check_data();
+ // 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".
+ // Using a block `{self.data}` here to force a copy instead of using `self.data`
+ // directly, because `write!` takes references to its formatting arguments and
+ // would thus borrow `self.data`. Since `Self`
+ // is a packed struct, that would create a possibly unaligned reference, which
+ // is UB.
+ write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
+ }
+}
+
+impl fmt::Display for ScalarInt {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.check_data();
+ write!(f, "{}", { self.data })
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
new file mode 100644
index 000000000..cb0137d2e
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -0,0 +1,239 @@
+use std::convert::TryInto;
+
+use crate::mir::interpret::{AllocId, ConstValue, Scalar};
+use crate::mir::Promoted;
+use crate::ty::subst::{InternalSubsts, SubstsRef};
+use crate::ty::ParamEnv;
+use crate::ty::{self, TyCtxt, TypeVisitable};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def_id::DefId;
+use rustc_macros::HashStable;
+use rustc_target::abi::Size;
+
+use super::ScalarInt;
+/// An unevaluated, potentially generic, constant.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
+#[derive(Hash, HashStable)]
+pub struct Unevaluated<'tcx, P = Option<Promoted>> {
+ pub def: ty::WithOptConstParam<DefId>,
+ pub substs: SubstsRef<'tcx>,
+ pub promoted: P,
+}
+
+impl<'tcx> Unevaluated<'tcx> {
+ #[inline]
+ pub fn shrink(self) -> Unevaluated<'tcx, ()> {
+ debug_assert_eq!(self.promoted, None);
+ Unevaluated { def: self.def, substs: self.substs, promoted: () }
+ }
+}
+
+impl<'tcx> Unevaluated<'tcx, ()> {
+ #[inline]
+ pub fn expand(self) -> Unevaluated<'tcx> {
+ Unevaluated { def: self.def, substs: self.substs, promoted: None }
+ }
+}
+
+impl<'tcx, P: Default> Unevaluated<'tcx, P> {
+ #[inline]
+ pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
+ Unevaluated { def, substs, promoted: Default::default() }
+ }
+}
+
+/// Represents a constant in Rust.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(Hash, HashStable)]
+pub enum ConstKind<'tcx> {
+ /// A const generic parameter.
+ Param(ty::ParamConst),
+
+ /// Infer the value of the const.
+ Infer(InferConst<'tcx>),
+
+ /// Bound const variable, used only when preparing a trait query.
+ Bound(ty::DebruijnIndex, ty::BoundVar),
+
+ /// A placeholder const - universally quantified higher-ranked const.
+ Placeholder(ty::PlaceholderConst<'tcx>),
+
+ /// 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(Unevaluated<'tcx>),
+
+ /// Used to hold computed value.
+ Value(ty::ValTree<'tcx>),
+
+ /// A placeholder for a const which could not be computed; this is
+ /// propagated to avoid useless error messages.
+ Error(ty::DelaySpanBugEmitted),
+}
+
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(ConstKind<'_>, 40);
+
+impl<'tcx> ConstKind<'tcx> {
+ #[inline]
+ pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
+ if let ConstKind::Value(val) = self { Some(val) } else { None }
+ }
+
+ #[inline]
+ pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
+ self.try_to_value()?.try_to_scalar()
+ }
+
+ #[inline]
+ pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
+ self.try_to_value()?.try_to_scalar_int()
+ }
+
+ #[inline]
+ pub fn try_to_bits(self, size: Size) -> Option<u128> {
+ self.try_to_scalar_int()?.to_bits(size).ok()
+ }
+
+ #[inline]
+ pub fn try_to_bool(self) -> Option<bool> {
+ self.try_to_scalar_int()?.try_into().ok()
+ }
+
+ #[inline]
+ pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+ self.try_to_value()?.try_to_machine_usize(tcx)
+ }
+}
+
+/// An inference variable for a const, for use in const generics.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
+#[derive(HashStable)]
+pub enum InferConst<'tcx> {
+ /// Infer the value of the const.
+ Var(ty::ConstVid<'tcx>),
+ /// A fresh const variable. See `infer::freshen` for more details.
+ Fresh(u32),
+}
+
+enum EvalMode {
+ Typeck,
+ Mir,
+}
+
+enum EvalResult<'tcx> {
+ ValTree(ty::ValTree<'tcx>),
+ ConstVal(ConstValue<'tcx>),
+}
+
+impl<'tcx> ConstKind<'tcx> {
+ #[inline]
+ /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
+ /// unevaluated constant.
+ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
+ self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
+ }
+
+ #[inline]
+ /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
+ /// return `None`.
+ // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
+ pub fn try_eval_for_mir(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
+ match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
+ Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
+ Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
+ Some(Err(e)) => Some(Err(e)),
+ None => None,
+ }
+ }
+
+ #[inline]
+ /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
+ /// return `None`.
+ // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
+ pub fn try_eval_for_typeck(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
+ match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
+ Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
+ Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
+ Some(Err(e)) => Some(Err(e)),
+ None => None,
+ }
+ }
+
+ #[inline]
+ fn try_eval_inner(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ eval_mode: EvalMode,
+ ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
+ if let ConstKind::Unevaluated(unevaluated) = self {
+ use crate::mir::interpret::ErrorHandled;
+
+ // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
+ // also does later, but we want to do it before checking for
+ // inference variables.
+ // Note that we erase regions *before* calling `with_reveal_all_normalized`,
+ // so that we don't try to invoke this query with
+ // any region variables.
+ let param_env_and = tcx
+ .erase_regions(param_env)
+ .with_reveal_all_normalized(tcx)
+ .and(tcx.erase_regions(unevaluated));
+
+ // HACK(eddyb) when the query key would contain inference variables,
+ // attempt using identity substs and `ParamEnv` instead, that will succeed
+ // when the expression doesn't depend on any parameters.
+ // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
+ // we can call `infcx.const_eval_resolve` which handles inference variables.
+ let param_env_and = if param_env_and.needs_infer() {
+ tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
+ def: unevaluated.def,
+ substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did),
+ promoted: unevaluated.promoted,
+ })
+ } else {
+ param_env_and
+ };
+
+ // FIXME(eddyb) maybe the `const_eval_*` methods should take
+ // `ty::ParamEnvAnd` instead of having them separate.
+ let (param_env, unevaluated) = param_env_and.into_parts();
+ // try to resolve e.g. associated constants to their definition on an impl, and then
+ // evaluate the const.
+ match eval_mode {
+ EvalMode::Typeck => {
+ match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
+ // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+ // and we use the original type, so nothing from `substs`
+ // (which may be identity substs, see above),
+ // can leak through `val` into the const we return.
+ Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
+ Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
+ Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+ }
+ }
+ EvalMode::Mir => {
+ match tcx.const_eval_resolve(param_env, unevaluated, None) {
+ // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+ // and we use the original type, so nothing from `substs`
+ // (which may be identity substs, see above),
+ // can leak through `val` into the const we return.
+ Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
+ Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
+ Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+ }
+ }
+ }
+ } else {
+ None
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
new file mode 100644
index 000000000..93707bb18
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -0,0 +1,104 @@
+use super::ScalarInt;
+use crate::mir::interpret::{AllocId, Scalar};
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
+
+#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(HashStable)]
+/// This datastructure is used to represent the value of constants used in the type system.
+///
+/// We explicitly choose a different datastructure from the way values are processed within
+/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have
+/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa.
+/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different
+/// `AllocId`s point to equal values. So we may end up with different representations for
+/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will
+/// have arbitrary values within that padding, even if the values of the struct are the same.
+///
+/// `ValTree` does not have this problem with representation, as it only contains integers or
+/// lists of (nested) `ValTree`.
+pub enum ValTree<'tcx> {
+ /// ZSTs, integers, `bool`, `char` are represented as scalars.
+ /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
+ /// of these types have the same representation.
+ Leaf(ScalarInt),
+
+ //SliceOrStr(ValSlice<'tcx>),
+ // dont use SliceOrStr for now
+ /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
+ /// listing their fields' values in order.
+ /// Enums are represented by storing their discriminant as a field, followed by all
+ /// the fields of the variant.
+ Branch(&'tcx [ValTree<'tcx>]),
+}
+
+impl<'tcx> ValTree<'tcx> {
+ pub fn zst() -> Self {
+ Self::Branch(&[])
+ }
+
+ #[inline]
+ pub fn unwrap_leaf(self) -> ScalarInt {
+ match self {
+ Self::Leaf(s) => s,
+ _ => bug!("expected leaf, got {:?}", self),
+ }
+ }
+
+ #[inline]
+ pub fn unwrap_branch(self) -> &'tcx [Self] {
+ match self {
+ Self::Branch(branch) => branch,
+ _ => bug!("expected branch, got {:?}", self),
+ }
+ }
+
+ pub fn from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self {
+ let branches = bytes.iter().map(|b| Self::Leaf(ScalarInt::from(*b)));
+ let interned = tcx.arena.alloc_from_iter(branches);
+
+ Self::Branch(interned)
+ }
+
+ pub fn from_scalar_int(i: ScalarInt) -> Self {
+ Self::Leaf(i)
+ }
+
+ pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
+ self.try_to_scalar_int().map(Scalar::Int)
+ }
+
+ pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
+ match self {
+ Self::Leaf(s) => Some(s),
+ Self::Branch(_) => None,
+ }
+ }
+
+ pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+ self.try_to_scalar_int().map(|s| s.try_to_machine_usize(tcx).ok()).flatten()
+ }
+
+ /// Get the values inside the ValTree as a slice of bytes. This only works for
+ /// constants with types &str, &[u8], or [u8; _].
+ pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
+ match ty.kind() {
+ ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
+ // `&str` can be interpreted as raw bytes
+ ty::Str => {}
+ // `&[u8]` can be interpreted as raw bytes
+ ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
+ // other `&_` can't be interpreted as raw bytes
+ _ => return None,
+ },
+ // `[u8; N]` can be interpreted as raw bytes
+ ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
+ // Otherwise, type cannot be interpreted as raw bytes
+ _ => return None,
+ }
+
+ Some(tcx.arena.alloc_from_iter(
+ self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().try_to_u8().unwrap()),
+ ))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
new file mode 100644
index 000000000..0a0f45ce1
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -0,0 +1,3018 @@
+//! Type context book-keeping.
+
+use crate::arena::Arena;
+use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
+use crate::hir::place::Place as HirPlace;
+use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
+use crate::lint::{struct_lint_level, LintLevelSource};
+use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
+use crate::middle::resolve_lifetime;
+use crate::middle::stability;
+use crate::mir::interpret::{self, Allocation, ConstAllocation};
+use crate::mir::{
+ Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
+};
+use crate::thir::Thir;
+use crate::traits;
+use crate::ty::query::{self, TyCtxtAt};
+use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
+use crate::ty::{
+ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
+ ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
+ FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
+ ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
+ RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
+};
+use rustc_ast as ast;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::{Interned, WithStableHash};
+use rustc_data_structures::memmap::Mmap;
+use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::steal::Steal;
+use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
+use rustc_data_structures::vec_map::VecMap;
+use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
+use rustc_hir::definitions::Definitions;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{
+ Constness, ExprKind, HirId, ImplItemKind, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet,
+ Node, TraitCandidate, TraitItemKind,
+};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_macros::HashStable;
+use rustc_middle::mir::FakeReadCause;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
+use rustc_session::config::{CrateType, OutputFilenames};
+use rustc_session::cstore::CrateStoreDyn;
+use rustc_session::lint::{Level, Lint};
+use rustc_session::Limit;
+use rustc_session::Session;
+use rustc_span::def_id::{DefPathHash, StableCrateId};
+use rustc_span::source_map::SourceMap;
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
+use rustc_target::spec::abi;
+use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags};
+
+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;
+
+use super::{ImplPolarity, RvalueScopes};
+
+pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
+ /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
+ fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
+ where
+ Self: Sized;
+
+ fn new_empty(source_map: &'tcx SourceMap) -> Self
+ where
+ Self: Sized;
+
+ fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
+
+ fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: FileEncoder) -> FileEncodeResult;
+}
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Interner for TyCtxt<'tcx> {
+ type AdtDef = ty::AdtDef<'tcx>;
+ type SubstsRef = ty::SubstsRef<'tcx>;
+ type DefId = DefId;
+ type Ty = Ty<'tcx>;
+ type Const = ty::Const<'tcx>;
+ type Region = Region<'tcx>;
+ type TypeAndMut = TypeAndMut<'tcx>;
+ type Mutability = hir::Mutability;
+ type Movability = hir::Movability;
+ type PolyFnSig = PolyFnSig<'tcx>;
+ type ListBinderExistentialPredicate = &'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>;
+ type BinderListTy = Binder<'tcx, &'tcx List<Ty<'tcx>>>;
+ type ListTy = &'tcx List<Ty<'tcx>>;
+ type ProjectionTy = ty::ProjectionTy<'tcx>;
+ type ParamTy = ParamTy;
+ type BoundTy = ty::BoundTy;
+ type PlaceholderType = ty::PlaceholderType;
+ type InferTy = InferTy;
+ type DelaySpanBugEmitted = DelaySpanBugEmitted;
+ type PredicateKind = ty::PredicateKind<'tcx>;
+ type AllocId = crate::mir::interpret::AllocId;
+
+ type EarlyBoundRegion = ty::EarlyBoundRegion;
+ type BoundRegion = ty::BoundRegion;
+ type FreeRegion = ty::FreeRegion;
+ type RegionVid = ty::RegionVid;
+ type PlaceholderRegion = ty::PlaceholderRegion;
+}
+
+/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
+/// except through the error-reporting functions on a [`tcx`][TyCtxt].
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub struct DelaySpanBugEmitted {
+ pub reported: ErrorGuaranteed,
+ _priv: (),
+}
+
+type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'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, WithStableHash<TyS<'tcx>>>,
+ substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
+ canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
+ region: InternedSet<'tcx, RegionKind<'tcx>>,
+ poly_existential_predicates:
+ InternedSet<'tcx, List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>>,
+ predicate: InternedSet<'tcx, PredicateS<'tcx>>,
+ predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
+ projs: InternedSet<'tcx, List<ProjectionKind>>,
+ place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
+ const_: InternedSet<'tcx, ConstS<'tcx>>,
+ const_allocation: InternedSet<'tcx, Allocation>,
+ bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
+ layout: InternedSet<'tcx, LayoutS<'tcx>>,
+ adt_def: InternedSet<'tcx, AdtDefData>,
+}
+
+impl<'tcx> CtxtInterners<'tcx> {
+ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
+ CtxtInterners {
+ arena,
+ type_: Default::default(),
+ substs: Default::default(),
+ region: Default::default(),
+ poly_existential_predicates: Default::default(),
+ canonical_var_infos: Default::default(),
+ predicate: Default::default(),
+ predicates: Default::default(),
+ projs: Default::default(),
+ place_elems: Default::default(),
+ const_: Default::default(),
+ const_allocation: Default::default(),
+ bound_variable_kinds: Default::default(),
+ layout: Default::default(),
+ adt_def: Default::default(),
+ }
+ }
+
+ /// Interns a type.
+ #[allow(rustc::usage_of_ty_tykind)]
+ #[inline(never)]
+ fn intern_ty(
+ &self,
+ kind: TyKind<'tcx>,
+ sess: &Session,
+ definitions: &rustc_hir::definitions::Definitions,
+ cstore: &CrateStoreDyn,
+ source_span: &IndexVec<LocalDefId, Span>,
+ ) -> Ty<'tcx> {
+ Ty(Interned::new_unchecked(
+ self.type_
+ .intern(kind, |kind| {
+ let flags = super::flags::FlagComputation::for_kind(&kind);
+
+ // It's impossible to hash inference regions (and will ICE), so we don't need to try to cache them.
+ // Without incremental, we rarely stable-hash types, so let's not do it proactively.
+ let stable_hash = if flags.flags.intersects(TypeFlags::HAS_RE_INFER)
+ || sess.opts.incremental.is_none()
+ {
+ Fingerprint::ZERO
+ } else {
+ let mut hasher = StableHasher::new();
+ let mut hcx = StableHashingContext::ignore_spans(
+ sess,
+ definitions,
+ cstore,
+ source_span,
+ );
+ kind.hash_stable(&mut hcx, &mut hasher);
+ hasher.finish()
+ };
+
+ let ty_struct = TyS {
+ kind,
+ flags: flags.flags,
+ outer_exclusive_binder: flags.outer_exclusive_binder,
+ };
+
+ InternedInSet(
+ self.arena.alloc(WithStableHash { internee: ty_struct, stable_hash }),
+ )
+ })
+ .0,
+ ))
+ }
+
+ #[inline(never)]
+ fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
+ Predicate(Interned::new_unchecked(
+ self.predicate
+ .intern(kind, |kind| {
+ let flags = super::flags::FlagComputation::for_predicate(kind);
+
+ let predicate_struct = PredicateS {
+ kind,
+ flags: flags.flags,
+ outer_exclusive_binder: flags.outer_exclusive_binder,
+ };
+
+ InternedInSet(self.arena.alloc(predicate_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 str_: Ty<'tcx>,
+ pub never: Ty<'tcx>,
+ pub self_param: 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 outside of type inference.
+ pub re_erased: Region<'tcx>,
+}
+
+pub struct CommonConsts<'tcx> {
+ pub unit: Const<'tcx>,
+}
+
+pub struct LocalTableInContext<'a, V> {
+ hir_owner: LocalDefId,
+ data: &'a ItemLocalMap<V>,
+}
+
+/// Validate that the given HirId (respectively its `local_id` part) can be
+/// safely used as a key in the maps of a TypeckResults. For that to be
+/// the case, the HirId must have the same `owner` as all the other IDs in
+/// this table (signified by `hir_owner`). 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.
+#[inline]
+fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
+ if hir_id.owner != hir_owner {
+ invalid_hir_id_for_typeck_results(hir_owner, hir_id);
+ }
+}
+
+#[cold]
+#[inline(never)]
+fn invalid_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
+ ty::tls::with(|tcx| {
+ bug!(
+ "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
+ tcx.hir().node_to_string(hir_id),
+ hir_id.owner,
+ hir_owner
+ )
+ });
+}
+
+impl<'a, V> LocalTableInContext<'a, V> {
+ pub fn contains_key(&self, id: hir::HirId) -> bool {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.contains_key(&id.local_id)
+ }
+
+ pub fn get(&self, id: hir::HirId) -> Option<&V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ 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> {
+ hir_owner: LocalDefId,
+ 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_results(self.hir_owner, id);
+ self.data.get_mut(&id.local_id)
+ }
+
+ pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.entry(id.local_id)
+ }
+
+ pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.insert(id.local_id, val)
+ }
+
+ pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.remove(&id.local_id)
+ }
+}
+
+/// 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 = expr;
+/// foo.await
+/// ...
+/// }
+/// ```
+///
+/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
+/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+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>,
+ /// Span of `.await` or `yield` expression.
+ pub yield_span: Span,
+ /// Expr which the type evaluated from.
+ pub expr: Option<hir::HirId>,
+}
+
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+ pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+ pub hir_owner: DefId,
+ pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+ pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct TypeckResults<'tcx> {
+ /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
+ pub hir_owner: LocalDefId,
+
+ /// Resolved definitions for `<T>::X` associated paths and
+ /// method calls, including those of overloaded operators.
+ type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
+
+ /// 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 outside inference. 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 THIR 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>>>,
+
+ /// Records the reasons that we picked the kind of each closure;
+ /// not all closures are present in the map.
+ closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
+
+ /// 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.
+ ///
+ /// This table also contains the "revealed" values for any `impl Trait`
+ /// that appear in the signature and whose values are being inferred
+ /// by this function.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::fmt::Debug;
+ /// fn foo(x: &u32) -> impl Debug { *x }
+ /// ```
+ ///
+ /// The function signature here would be:
+ ///
+ /// ```ignore (illustrative)
+ /// for<'a> fn(&'a u32) -> Foo
+ /// ```
+ ///
+ /// where `Foo` is an opaque type created for this function.
+ ///
+ ///
+ /// The *liberated* form of this would be
+ ///
+ /// ```ignore (illustrative)
+ /// fn(&'a u32) -> u32
+ /// ```
+ ///
+ /// Note that `'a` is not bound (it would be an `ReFree`) and
+ /// that the `Foo` opaque type is replaced by its hidden type.
+ 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<FxHashSet<LocalDefId>>,
+
+ /// If any errors occurred while type-checking this body,
+ /// this field will be set to `Some(ErrorGuaranteed)`.
+ pub tainted_by_errors: Option<ErrorGuaranteed>,
+
+ /// All the opaque types that have hidden types set
+ /// by this function. For return-position-impl-trait we also store the
+ /// type here, so that mir-borrowck can figure out hidden types,
+ /// even if they are only set in dead code (which doesn't show up in MIR).
+ /// For type-alias-impl-trait, this map is only used to prevent query cycles,
+ /// so the hidden types are all `None`.
+ pub concrete_opaque_types: VecMap<LocalDefId, Option<Ty<'tcx>>>,
+
+ /// Tracks the minimum captures required for a closure;
+ /// see `MinCaptureInformationMap` for more details.
+ pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
+
+ /// Tracks the fake reads required for a closure and the reason for the fake read.
+ /// When performing pattern matching for closures, there are times we don't end up
+ /// reading places that are mentioned in a closure (because of _ patterns). However,
+ /// to ensure the places are initialized, we introduce fake reads.
+ /// Consider these two examples:
+ /// ``` (discriminant matching with only wildcard arm)
+ /// let x: u8;
+ /// let c = || match x { _ => () };
+ /// ```
+ /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
+ /// want to capture it. However, we do still want an error here, because `x` should have
+ /// to be initialized at the point where c is created. Therefore, we add a "fake read"
+ /// instead.
+ /// ``` (destructured assignments)
+ /// let c = || {
+ /// let (t1, t2) = t;
+ /// }
+ /// ```
+ /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
+ /// we never capture `t`. This becomes an issue when we build MIR as we require
+ /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
+ /// issue by fake reading `t`.
+ pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
+
+ /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
+ /// by applying extended parameter rules.
+ /// Details may be find in `rustc_typeck::check::rvalue_scopes`.
+ pub rvalue_scopes: RvalueScopes,
+
+ /// 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: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+
+ /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
+ /// as `&[u8]`, depending on the pattern in which they are used.
+ /// This hashset records all instances where we behave
+ /// like this to allow `const_to_pat` to reliably handle this situation.
+ pub treat_byte_string_as_slice: ItemLocalSet,
+
+ /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
+ /// on closure size.
+ pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
+}
+
+impl<'tcx> TypeckResults<'tcx> {
+ pub fn new(hir_owner: LocalDefId) -> TypeckResults<'tcx> {
+ TypeckResults {
+ hir_owner,
+ 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(),
+ 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: None,
+ concrete_opaque_types: Default::default(),
+ closure_min_captures: Default::default(),
+ closure_fake_reads: Default::default(),
+ rvalue_scopes: Default::default(),
+ generator_interior_types: ty::Binder::dummy(Default::default()),
+ treat_byte_string_as_slice: Default::default(),
+ closure_size_eval: 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(..) | hir::QPath::LangItem(..) => 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), ErrorGuaranteed>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
+ }
+
+ pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ 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), ErrorGuaranteed>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
+ }
+
+ pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
+ }
+
+ pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
+ }
+
+ pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
+ }
+
+ pub fn user_provided_types_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
+ }
+
+ pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
+ }
+
+ pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
+ }
+
+ pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+ let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+ vec.iter()
+ .map(|item| {
+ GeneratorInteriorTypeCause {
+ ty: item.ty,
+ span: item.span,
+ scope_span: item.scope_span,
+ yield_span: item.yield_span,
+ expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+ }
+ })
+ .collect::<Vec<_>>()
+ });
+ GeneratorDiagnosticData {
+ generator_interior_types: generator_interior_type,
+ hir_owner: self.hir_owner.to_def_id(),
+ nodes_types: self.node_types.clone(),
+ adjustments: self.adjustments.clone(),
+ }
+ }
+
+ 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_results(self.hir_owner, id);
+ self.node_types.get(&id.local_id).cloned()
+ }
+
+ pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
+ }
+
+ pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ 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_results(self.hir_owner, id);
+ 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)
+ }
+
+ // 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 { hir_owner: self.hir_owner, data: &self.adjustments }
+ }
+
+ pub fn adjustments_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
+ }
+
+ pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
+ validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
+ 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;
+ }
+
+ matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
+ }
+
+ 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 { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
+ }
+
+ pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
+ }
+
+ pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
+ }
+
+ pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
+ }
+
+ /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
+ /// by the closure.
+ pub fn closure_min_captures_flattened(
+ &self,
+ closure_def_id: LocalDefId,
+ ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
+ self.closure_min_captures
+ .get(&closure_def_id)
+ .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
+ .into_iter()
+ .flatten()
+ }
+
+ pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
+ }
+
+ pub fn closure_kind_origins_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
+ }
+
+ pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
+ }
+
+ pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
+ }
+
+ pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
+ }
+
+ pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
+ }
+
+ pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
+ validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
+ 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
+ }
+}
+
+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, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, 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<'tcx> 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;
+ }
+
+ iter::zip(user_substs.substs, 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.var
+ }
+ _ => false,
+ },
+
+ GenericArgKind::Const(ct) => match ct.kind() {
+ 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, 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>,
+ sess: &Session,
+ definitions: &rustc_hir::definitions::Definitions,
+ cstore: &CrateStoreDyn,
+ source_span: &IndexVec<LocalDefId, Span>,
+ ) -> CommonTypes<'tcx> {
+ let mk = |ty| interners.intern_ty(ty, sess, definitions, cstore, source_span);
+
+ CommonTypes {
+ unit: mk(Tuple(List::empty())),
+ bool: mk(Bool),
+ char: mk(Char),
+ never: mk(Never),
+ isize: mk(Int(ty::IntTy::Isize)),
+ i8: mk(Int(ty::IntTy::I8)),
+ i16: mk(Int(ty::IntTy::I16)),
+ i32: mk(Int(ty::IntTy::I32)),
+ i64: mk(Int(ty::IntTy::I64)),
+ i128: mk(Int(ty::IntTy::I128)),
+ usize: mk(Uint(ty::UintTy::Usize)),
+ u8: mk(Uint(ty::UintTy::U8)),
+ u16: mk(Uint(ty::UintTy::U16)),
+ u32: mk(Uint(ty::UintTy::U32)),
+ u64: mk(Uint(ty::UintTy::U64)),
+ u128: mk(Uint(ty::UintTy::U128)),
+ f32: mk(Float(ty::FloatTy::F32)),
+ f64: mk(Float(ty::FloatTy::F64)),
+ str_: mk(Str),
+ 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| {
+ Region(Interned::new_unchecked(
+ interners.region.intern(r, |r| InternedInSet(interners.arena.alloc(r))).0,
+ ))
+ };
+
+ CommonLifetimes {
+ re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)),
+ re_static: mk(ty::ReStatic),
+ re_erased: mk(ty::ReErased),
+ }
+ }
+}
+
+impl<'tcx> CommonConsts<'tcx> {
+ fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> {
+ let mk_const = |c| {
+ Const(Interned::new_unchecked(
+ interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0,
+ ))
+ };
+
+ CommonConsts {
+ unit: mk_const(ty::ConstS {
+ kind: ty::ConstKind::Value(ty::ValTree::zst()),
+ ty: types.unit,
+ }),
+ }
+ }
+}
+
+// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime
+// conflict.
+#[derive(Debug)]
+pub struct FreeRegionInfo {
+ // `LocalDefId` corresponding to FreeRegion
+ pub def_id: LocalDefId,
+ // the bound region corresponding to FreeRegion
+ pub boundregion: ty::BoundRegionKind,
+ // 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 dev guide] for more details.
+///
+/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html
+#[derive(Copy, Clone)]
+#[rustc_diagnostic_item = "TyCtxt"]
+#[rustc_pass_by_value]
+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>>,
+ pub hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
+
+ interners: CtxtInterners<'tcx>,
+
+ 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>,
+
+ definitions: RwLock<Definitions>,
+ cstore: Box<CrateStoreDyn>,
+
+ /// Output of the resolver.
+ pub(crate) untracked_resolutions: ty::ResolverOutputs,
+ untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>,
+ /// The entire crate as AST. This field serves as the input for the hir_crate query,
+ /// which lowers it from AST to HIR. It must not be read or used by anything else.
+ pub untracked_crate: Steal<Lrc<ast::Crate>>,
+
+ /// This provides access to the incremental compilation 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.
+ /// This is `None` if we are not incremental compilation mode
+ pub on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
+
+ pub queries: &'tcx dyn query::QueryEngine<'tcx>,
+ pub query_caches: query::QueryCaches<'tcx>,
+ query_kinds: &'tcx [DepKindStruct],
+
+ // Internal caches for metadata decoding. No need to track deps on this.
+ pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+ pub pred_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Predicate<'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.
+ crate_name: Symbol,
+
+ /// Data layout specification for the current target.
+ pub data_layout: TargetDataLayout,
+
+ /// Stores memory for globals (statics/consts).
+ pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
+
+ output_filenames: Arc<OutputFilenames>,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// Expects a body and returns its codegen attributes.
+ ///
+ /// Unlike `codegen_fn_attrs`, this returns `CodegenFnAttrs::EMPTY` for
+ /// constants.
+ pub fn body_codegen_attrs(self, def_id: DefId) -> &'tcx CodegenFnAttrs {
+ let def_kind = self.def_kind(def_id);
+ if def_kind.has_codegen_attrs() {
+ self.codegen_fn_attrs(def_id)
+ } else if matches!(
+ def_kind,
+ DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
+ ) {
+ CodegenFnAttrs::EMPTY
+ } else {
+ bug!(
+ "body_codegen_fn_attrs called on unexpected definition: {:?} {:?}",
+ def_id,
+ def_kind
+ )
+ }
+ }
+
+ pub fn typeck_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<LocalDefId>,
+ ) -> &'tcx TypeckResults<'tcx> {
+ if let Some(param_did) = def.const_param_did {
+ self.typeck_const_arg((def.did, param_did))
+ } else {
+ self.typeck(def.did)
+ }
+ }
+
+ pub fn mir_borrowck_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<LocalDefId>,
+ ) -> &'tcx BorrowCheckResult<'tcx> {
+ if let Some(param_did) = def.const_param_did {
+ self.mir_borrowck_const_arg((def.did, param_did))
+ } else {
+ self.mir_borrowck(def.did)
+ }
+ }
+
+ pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
+ self.arena.alloc(Steal::new(thir))
+ }
+
+ pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal<Body<'tcx>> {
+ self.arena.alloc(Steal::new(mir))
+ }
+
+ pub fn alloc_steal_promoted(
+ self,
+ promoted: IndexVec<Promoted, Body<'tcx>>,
+ ) -> &'tcx Steal<IndexVec<Promoted, Body<'tcx>>> {
+ self.arena.alloc(Steal::new(promoted))
+ }
+
+ pub fn alloc_adt_def(
+ self,
+ did: DefId,
+ kind: AdtKind,
+ variants: IndexVec<VariantIdx, ty::VariantDef>,
+ repr: ReprOptions,
+ ) -> ty::AdtDef<'tcx> {
+ self.intern_adt_def(ty::AdtDefData::new(self, did, kind, variants, repr))
+ }
+
+ /// 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_bytes_byte_aligned_immutable(bytes);
+ let alloc = self.intern_const_alloc(alloc);
+ self.create_memory_alloc(alloc)
+ }
+
+ /// Returns a range of the start/end indices specified with the
+ /// `rustc_layout_scalar_valid_range` attribute.
+ // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
+ pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
+ let get = |name| {
+ let Some(attr) = self.get_attr(def_id, name) else {
+ return Bound::Unbounded;
+ };
+ debug!("layout_scalar_valid_range: attr={:?}", attr);
+ if let Some(
+ &[
+ ast::NestedMetaItem::Literal(ast::Lit {
+ kind: ast::LitKind::Int(a, _), ..
+ }),
+ ],
+ ) = attr.meta_item_list().as_deref()
+ {
+ Bound::Included(a)
+ } else {
+ self.sess
+ .delay_span_bug(attr.span, "invalid rustc_layout_scalar_valid_range attribute");
+ Bound::Unbounded
+ }
+ };
+ (
+ get(sym::rustc_layout_scalar_valid_range_start),
+ get(sym::rustc_layout_scalar_valid_range_end),
+ )
+ }
+
+ pub fn lift<T: 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>,
+ arena: &'tcx WorkerLocal<Arena<'tcx>>,
+ hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
+ definitions: Definitions,
+ cstore: Box<CrateStoreDyn>,
+ untracked_resolutions: ty::ResolverOutputs,
+ untracked_resolver_for_lowering: ty::ResolverAstLowering,
+ krate: Lrc<ast::Crate>,
+ dep_graph: DepGraph,
+ on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
+ queries: &'tcx dyn query::QueryEngine<'tcx>,
+ query_kinds: &'tcx [DepKindStruct],
+ crate_name: &str,
+ output_filenames: OutputFilenames,
+ ) -> GlobalCtxt<'tcx> {
+ let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
+ s.fatal(&err);
+ });
+ let interners = CtxtInterners::new(arena);
+ let common_types = CommonTypes::new(
+ &interners,
+ s,
+ &definitions,
+ &*cstore,
+ // This is only used to create a stable hashing context.
+ &untracked_resolutions.source_span,
+ );
+ let common_lifetimes = CommonLifetimes::new(&interners);
+ let common_consts = CommonConsts::new(&interners, &common_types);
+
+ GlobalCtxt {
+ sess: s,
+ lint_store,
+ arena,
+ hir_arena,
+ interners,
+ dep_graph,
+ definitions: RwLock::new(definitions),
+ cstore,
+ prof: s.prof.clone(),
+ types: common_types,
+ lifetimes: common_lifetimes,
+ consts: common_consts,
+ untracked_resolutions,
+ untracked_resolver_for_lowering: Steal::new(untracked_resolver_for_lowering),
+ untracked_crate: Steal::new(krate),
+ on_disk_cache,
+ queries,
+ query_caches: query::QueryCaches::default(),
+ query_kinds,
+ ty_rcache: Default::default(),
+ pred_rcache: Default::default(),
+ selection_cache: Default::default(),
+ evaluation_cache: Default::default(),
+ crate_name: Symbol::intern(crate_name),
+ data_layout,
+ alloc_map: Lock::new(interpret::AllocMap::new()),
+ output_filenames: Arc::new(output_filenames),
+ }
+ }
+
+ pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+ &self.query_kinds[k as usize]
+ }
+
+ /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
+ #[track_caller]
+ pub fn ty_error(self) -> Ty<'tcx> {
+ self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported")
+ }
+
+ /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
+ /// ensure it gets used.
+ #[track_caller]
+ pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
+ let reported = self.sess.delay_span_bug(span, msg);
+ self.mk_ty(Error(DelaySpanBugEmitted { reported, _priv: () }))
+ }
+
+ /// Like [TyCtxt::ty_error] but for constants.
+ #[track_caller]
+ pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> {
+ self.const_error_with_message(
+ ty,
+ DUMMY_SP,
+ "ty::ConstKind::Error constructed but no error reported",
+ )
+ }
+
+ /// Like [TyCtxt::ty_error_with_message] but for constants.
+ #[track_caller]
+ pub fn const_error_with_message<S: Into<MultiSpan>>(
+ self,
+ ty: Ty<'tcx>,
+ span: S,
+ msg: &str,
+ ) -> Const<'tcx> {
+ let reported = self.sess.delay_span_bug(span, msg);
+ self.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Error(DelaySpanBugEmitted { reported, _priv: () }),
+ ty,
+ })
+ }
+
+ pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
+ let cname = self.crate_name(LOCAL_CRATE);
+ self.sess.consider_optimizing(cname.as_str(), msg)
+ }
+
+ /// Obtain all lang items of this crate and all dependencies (recursively)
+ pub fn lang_items(self) -> &'tcx rustc_hir::lang_items::LanguageItems {
+ self.get_lang_items(())
+ }
+
+ /// 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(()).name_to_id.get(&name).copied()
+ }
+
+ /// Obtain the diagnostic item's name
+ pub fn get_diagnostic_name(self, id: DefId) -> Option<Symbol> {
+ self.diagnostic_items(id.krate).id_to_name.get(&id).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).name_to_id.get(&name) == Some(&did)
+ }
+
+ pub fn stability(self) -> &'tcx stability::Index {
+ self.stability_index(())
+ }
+
+ pub fn features(self) -> &'tcx rustc_feature::Features {
+ self.features_query(())
+ }
+
+ pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey {
+ // Accessing the DefKey is ok, since it is part of DefPathHash.
+ if let Some(id) = id.as_local() {
+ self.definitions_untracked().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) -> rustc_hir::definitions::DefPath {
+ // Accessing the DefPath is ok, since it is part of DefPathHash.
+ if let Some(id) = id.as_local() {
+ self.definitions_untracked().def_path(id)
+ } else {
+ self.cstore.def_path(id)
+ }
+ }
+
+ #[inline]
+ pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
+ // Accessing the DefPathHash is ok, it is incr. comp. stable.
+ if let Some(def_id) = def_id.as_local() {
+ self.definitions_untracked().def_path_hash(def_id)
+ } else {
+ self.cstore.def_path_hash(def_id)
+ }
+ }
+
+ #[inline]
+ pub fn stable_crate_id(self, crate_num: CrateNum) -> StableCrateId {
+ if crate_num == LOCAL_CRATE {
+ self.sess.local_stable_crate_id()
+ } else {
+ self.cstore.stable_crate_id(crate_num)
+ }
+ }
+
+ /// Maps a StableCrateId to the corresponding CrateNum. This method assumes
+ /// that the crate in question has already been loaded by the CrateStore.
+ #[inline]
+ pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> CrateNum {
+ if stable_crate_id == self.sess.local_stable_crate_id() {
+ LOCAL_CRATE
+ } else {
+ self.cstore.stable_crate_id_to_crate_num(stable_crate_id)
+ }
+ }
+
+ /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
+ /// session, if it still exists. This is used during incremental compilation to
+ /// turn a deserialized `DefPathHash` into its current `DefId`.
+ pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() -> !) -> DefId {
+ debug!("def_path_hash_to_def_id({:?})", hash);
+
+ let stable_crate_id = hash.stable_crate_id();
+
+ // If this is a DefPathHash from the local crate, we can look up the
+ // DefId in the tcx's `Definitions`.
+ if stable_crate_id == self.sess.local_stable_crate_id() {
+ self.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id()
+ } else {
+ // If this is a DefPathHash from an upstream crate, let the CrateStore map
+ // it to a DefId.
+ let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id);
+ self.cstore.def_path_hash_to_def_id(cnum, hash)
+ }
+ }
+
+ 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 stable crate id since this code is called from debug!()
+ // statements within the query system and we'd run into endless
+ // recursion otherwise.
+ let (crate_name, stable_crate_id) = if def_id.is_local() {
+ (self.crate_name, self.sess.local_stable_crate_id())
+ } else {
+ let cstore = &self.cstore;
+ (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
+ };
+
+ format!(
+ "{}[{:04x}]{}",
+ crate_name,
+ // Don't print the whole stable crate id. That's just
+ // annoying in debug output.
+ stable_crate_id.to_u64() >> 8 * 6,
+ self.def_path(def_id).to_string_no_crate_verbose()
+ )
+ }
+
+ /// Create a new definition within the incr. comp. engine.
+ pub fn create_def(self, parent: LocalDefId, data: hir::definitions::DefPathData) -> LocalDefId {
+ // This function modifies `self.definitions` using a side-effect.
+ // We need to ensure that these side effects are re-run by the incr. comp. engine.
+ // Depending on the forever-red node will tell the graph that the calling query
+ // needs to be re-evaluated.
+ use rustc_query_system::dep_graph::DepNodeIndex;
+ self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
+
+ // The following call has the side effect of modifying the tables inside `definitions`.
+ // These very tables are relied on by the incr. comp. engine to decode DepNodes and to
+ // decode the on-disk cache.
+ //
+ // Any LocalDefId which is used within queries, either as key or result, either:
+ // - has been created before the construction of the TyCtxt;
+ // - has been created by this call to `create_def`.
+ // As a consequence, this LocalDefId is always re-created before it is needed by the incr.
+ // comp. engine itself.
+ //
+ // This call also writes to the value of `source_span` and `expn_that_defined` queries.
+ // This is fine because:
+ // - those queries are `eval_always` so we won't miss their result changing;
+ // - this write will have happened before these queries are called.
+ self.definitions.write().create_def(parent, data)
+ }
+
+ pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
+ // Create a dependency to the crate to be sure we re-execute this when the amount of
+ // definitions change.
+ self.ensure().hir_crate(());
+ // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+ // while iterating. If some query needs to add definitions, it should be `ensure`d above.
+ let definitions = self.definitions.leak();
+ definitions.iter_local_def_id()
+ }
+
+ pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
+ // Create a dependency to the crate to be sure we reexcute this when the amount of
+ // definitions change.
+ self.ensure().hir_crate(());
+ // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+ // while iterating. If some query needs to add definitions, it should be `ensure`d above.
+ let definitions = self.definitions.leak();
+ definitions.def_path_table()
+ }
+
+ pub fn def_path_hash_to_def_index_map(
+ self,
+ ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
+ // Create a dependency to the crate to be sure we reexcute this when the amount of
+ // definitions change.
+ self.ensure().hir_crate(());
+ // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+ // while iterating. If some query needs to add definitions, it should be `ensure`d above.
+ let definitions = self.definitions.leak();
+ definitions.def_path_hash_to_def_index_map()
+ }
+
+ /// 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_untracked(self) -> &'tcx CrateStoreDyn {
+ &*self.cstore
+ }
+
+ /// Note that this is *untracked* and should only be used within the query
+ /// system if the result is otherwise tracked through queries
+ #[inline]
+ pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> {
+ self.definitions.read()
+ }
+
+ /// Note that this is *untracked* and should only be used within the query
+ /// system if the result is otherwise tracked through queries
+ #[inline]
+ pub fn source_span_untracked(self, def_id: LocalDefId) -> Span {
+ self.untracked_resolutions.source_span.get(def_id).copied().unwrap_or(DUMMY_SP)
+ }
+
+ #[inline(always)]
+ pub fn with_stable_hashing_context<R>(
+ self,
+ f: impl FnOnce(StableHashingContext<'_>) -> R,
+ ) -> R {
+ let definitions = self.definitions_untracked();
+ let hcx = StableHashingContext::new(
+ self.sess,
+ &*definitions,
+ &*self.cstore,
+ &self.untracked_resolutions.source_span,
+ );
+ f(hcx)
+ }
+
+ pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeResult {
+ self.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder))
+ }
+
+ /// If `true`, we should use lazy normalization for constants, otherwise
+ /// we still evaluate them eagerly.
+ #[inline]
+ pub fn lazy_normalization(self) -> bool {
+ let features = self.features();
+ // Note: We only use lazy normalization for generic const expressions.
+ features.generic_const_exprs
+ }
+
+ #[inline]
+ pub fn local_crate_exports_generics(self) -> bool {
+ debug_assert!(self.sess.opts.share_generics());
+
+ self.sess.crate_types().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 `BoundRegionKind` 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.expect_local(), free_region.bound_region)
+ }
+ ty::ReEarlyBound(ref ebr) => (
+ self.local_parent(ebr.def_id.expect_local()),
+ ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
+ ),
+ _ => return None, // not a free region
+ };
+
+ let is_impl_item = match self.hir().find_by_def_id(suitable_region_binding_scope) {
+ Some(Node::Item(..) | Node::TraitItem(..)) => false,
+ Some(Node::ImplItem(..)) => {
+ self.is_bound_region_in_impl_item(suitable_region_binding_scope)
+ }
+ _ => return None,
+ };
+
+ Some(FreeRegionInfo {
+ def_id: suitable_region_binding_scope,
+ boundregion: bound_region,
+ is_impl_item,
+ })
+ }
+
+ /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type.
+ pub fn return_type_impl_or_dyn_traits(
+ self,
+ scope_def_id: LocalDefId,
+ ) -> Vec<&'tcx hir::Ty<'tcx>> {
+ let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
+ let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) else {
+ return vec![];
+ };
+
+ let mut v = TraitObjectVisitor(vec![], self.hir());
+ v.visit_ty(hir_output);
+ v.0
+ }
+
+ pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
+ // `type_of()` will fail on these (#55796, #86483), so only allow `fn`s or closures.
+ match self.hir().get_by_def_id(scope_def_id) {
+ Node::Item(&hir::Item { kind: ItemKind::Fn(..), .. }) => {}
+ Node::TraitItem(&hir::TraitItem { kind: TraitItemKind::Fn(..), .. }) => {}
+ Node::ImplItem(&hir::ImplItem { kind: ImplItemKind::Fn(..), .. }) => {}
+ Node::Expr(&hir::Expr { kind: ExprKind::Closure { .. }, .. }) => {}
+ _ => return None,
+ }
+
+ 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 hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
+ 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: LocalDefId) -> bool {
+ let container_id = self.parent(suitable_region_binding_scope.to_def_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.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.bound_type_of(self.require_lang_item(LangItem::PanicLocation, 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_kind(def_id) {
+ DefKind::Generator => match self.generator_kind(def_id).unwrap() {
+ rustc_hir::GeneratorKind::Async(..) => ("an", "async closure"),
+ rustc_hir::GeneratorKind::Gen => ("a", "generator"),
+ },
+ def_kind => (def_kind.article(), def_kind.descr(def_id)),
+ }
+ }
+
+ pub fn type_length_limit(self) -> Limit {
+ self.limits(()).type_length_limit
+ }
+
+ pub fn recursion_limit(self) -> Limit {
+ self.limits(()).recursion_limit
+ }
+
+ pub fn move_size_limit(self) -> Limit {
+ self.limits(()).move_size_limit
+ }
+
+ pub fn const_eval_limit(self) -> Limit {
+ self.limits(()).const_eval_limit
+ }
+
+ pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
+ iter::once(LOCAL_CRATE)
+ .chain(self.crates(()).iter().copied())
+ .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
+ }
+}
+
+/// 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(&InternedInSet(&*self.0.0)) {
+ // SAFETY: `self` is interned and therefore valid
+ // for the entire lifetime of the `TyCtxt`.
+ Some(unsafe { mem::transmute(self) })
+ } else {
+ None
+ }
+ }
+ }
+ };
+}
+
+// Can't use the macros as we have reuse the `substs` here.
+//
+// See `intern_type_list` for more info.
+impl<'a, 'tcx> Lift<'tcx> for &'a List<Ty<'a>> {
+ type Lifted = &'tcx List<Ty<'tcx>>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ if self.is_empty() {
+ return Some(List::empty());
+ }
+ if tcx.interners.substs.contains_pointer_to(&InternedInSet(self.as_substs())) {
+ // SAFETY: `self` is interned and therefore valid
+ // for the entire lifetime of the `TyCtxt`.
+ Some(unsafe { mem::transmute::<&'a List<Ty<'a>>, &'tcx List<Ty<'tcx>>>(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(&InternedInSet(self)) {
+ Some(unsafe { mem::transmute(self) })
+ } else {
+ None
+ }
+ }
+ }
+ };
+}
+
+nop_lift! {type_; Ty<'a> => Ty<'tcx>}
+nop_lift! {region; Region<'a> => Region<'tcx>}
+nop_lift! {const_; Const<'a> => Const<'tcx>}
+nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
+nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
+
+nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>}
+nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>}
+nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
+nop_list_lift! {projs; ProjectionKind => ProjectionKind}
+nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
+
+// This is the impl for `&'a InternalSubsts<'a>`.
+nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
+
+CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } }
+
+pub mod tls {
+ use super::{ptr_eq, GlobalCtxt, TyCtxt};
+
+ use crate::dep_graph::TaskDepsRef;
+ use crate::ty::query;
+ use rustc_data_structures::sync::{self, Lock};
+ use rustc_data_structures::thin_vec::ThinVec;
+ 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`.
+ 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: TaskDepsRef<'a>,
+ }
+
+ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
+ pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
+ let tcx = TyCtxt { gcx };
+ ImplicitCtxt {
+ tcx,
+ query: None,
+ diagnostics: None,
+ layout_depth: 0,
+ task_deps: TaskDepsRef::Ignore,
+ }
+ }
+ }
+
+ /// 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]
+ pub 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> = const { 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 = rustc_data_structures::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))
+ }
+
+ /// 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 an `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 is the same 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 is different 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 {
+ ($fmt: expr, $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::InternedInSet;
+
+ #[derive(Copy, Clone)]
+ struct DebugStat {
+ total: usize,
+ lt_infer: usize,
+ ty_infer: usize,
+ ct_infer: usize,
+ all_infer: usize,
+ }
+
+ pub fn go(fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'_>) -> std::fmt::Result {
+ 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 &InternedInSet(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 }
+ }
+ writeln!(fmt, "Ty interner total ty lt ct all")?;
+ $(writeln!(fmt, " {: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)?;
+ )*
+ writeln!(fmt, " 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($fmt, $ctxt)
+ }}
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn debug_stats(self) -> impl std::fmt::Debug + 'tcx {
+ struct DebugStats<'tcx>(TyCtxt<'tcx>);
+
+ impl<'tcx> std::fmt::Debug for DebugStats<'tcx> {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ sty_debug_print!(
+ fmt,
+ self.0,
+ Adt,
+ Array,
+ Slice,
+ RawPtr,
+ Ref,
+ FnDef,
+ FnPtr,
+ Placeholder,
+ Generator,
+ GeneratorWitness,
+ Dynamic,
+ Closure,
+ Tuple,
+ Bound,
+ Param,
+ Infer,
+ Projection,
+ Opaque,
+ Foreign
+ )?;
+
+ writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?;
+ writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
+ writeln!(
+ fmt,
+ "Const Allocation interner: #{}",
+ self.0.interners.const_allocation.len()
+ )?;
+ writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?;
+
+ Ok(())
+ }
+ }
+
+ DebugStats(self)
+ }
+}
+
+// This type holds a `T` in the interner. The `T` is stored in the arena and
+// this type just holds a pointer to it, but it still effectively owns it. It
+// impls `Borrow` so that it can be looked up using the original
+// (non-arena-memory-owning) types.
+struct InternedInSet<'tcx, T: ?Sized>(&'tcx T);
+
+impl<'tcx, T: 'tcx + ?Sized> Clone for InternedInSet<'tcx, T> {
+ fn clone(&self) -> Self {
+ InternedInSet(self.0)
+ }
+}
+
+impl<'tcx, T: 'tcx + ?Sized> Copy for InternedInSet<'tcx, T> {}
+
+impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> {
+ fn into_pointer(&self) -> *const () {
+ self.0 as *const _ as *const ()
+ }
+}
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
+ fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
+ &self.0.kind
+ }
+}
+
+impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
+ fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<TyS<'tcx>>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
+ self.0.kind == other.0.kind
+ }
+}
+
+impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {}
+
+impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
+ self.0.kind.hash(s)
+ }
+}
+
+impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for InternedInSet<'tcx, PredicateS<'tcx>> {
+ fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
+ &self.0.kind
+ }
+}
+
+impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> {
+ fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
+ self.0.kind == other.0.kind
+ }
+}
+
+impl<'tcx> Eq for InternedInSet<'tcx, PredicateS<'tcx>> {}
+
+impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
+ self.0.kind.hash(s)
+ }
+}
+
+impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, List<T>> {
+ fn borrow<'a>(&'a self) -> &'a [T] {
+ &self.0[..]
+ }
+}
+
+impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, List<T>> {
+ fn eq(&self, other: &InternedInSet<'tcx, List<T>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
+ self.0[..] == other.0[..]
+ }
+}
+
+impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, List<T>> {}
+
+impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
+ self.0[..].hash(s)
+ }
+}
+
+macro_rules! direct_interners {
+ ($($name:ident: $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
+ $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
+ fn borrow<'a>(&'a self) -> &'a $ty {
+ &self.0
+ }
+ }
+
+ impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
+ fn eq(&self, other: &Self) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+ // equals `x == y`.
+ self.0 == other.0
+ }
+ }
+
+ impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
+
+ impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) ==
+ // x.hash(s)`.
+ self.0.hash(s)
+ }
+ }
+
+ impl<'tcx> TyCtxt<'tcx> {
+ pub fn $method(self, v: $ty) -> $ret_ty {
+ $ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| {
+ InternedInSet(self.interners.arena.alloc(v))
+ }).0))
+ }
+ })+
+ }
+}
+
+direct_interners! {
+ region: mk_region(RegionKind<'tcx>): Region -> Region<'tcx>,
+ const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+ const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
+ layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
+ adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'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, || {
+ InternedInSet(List::from_arena(&*self.arena, v))
+ }).0
+ })+
+ }
+ );
+}
+
+slice_interners!(
+ substs: _intern_substs(GenericArg<'tcx>),
+ canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>),
+ poly_existential_predicates:
+ _intern_poly_existential_predicates(ty::Binder<'tcx, ExistentialPredicate<'tcx>>),
+ predicates: _intern_predicates(Predicate<'tcx>),
+ projs: _intern_projs(ProjectionKind),
+ place_elems: _intern_place_elems(PlaceElem<'tcx>),
+ bound_variable_kinds: _intern_bound_variable_kinds(ty::BoundVariableKind),
+);
+
+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 the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
+ /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
+ pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+ self.super_traits_of(trait_def_id).any(|trait_did| {
+ self.associated_items(trait_did)
+ .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did)
+ .is_some()
+ })
+ }
+
+ /// Given a `ty`, return whether it's an `impl Future<...>`.
+ pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
+ let ty::Opaque(def_id, _) = ty.kind() else { return false };
+ let future_trait = self.lang_items().future_trait().unwrap();
+
+ self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
+ let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
+ return false;
+ };
+ trait_predicate.trait_ref.def_id == future_trait
+ && trait_predicate.polarity == ImplPolarity::Positive
+ })
+ }
+
+ /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
+ /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
+ /// to identify which traits may define a given associated type to help avoid cycle errors.
+ /// Returns a `DefId` iterator.
+ fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
+ let mut set = FxHashSet::default();
+ let mut stack = vec![trait_def_id];
+
+ set.insert(trait_def_id);
+
+ iter::from_fn(move || -> Option<DefId> {
+ let trait_did = stack.pop()?;
+ let generic_predicates = self.super_predicates_of(trait_did);
+
+ for (predicate, _) in generic_predicates.predicates {
+ if let ty::PredicateKind::Trait(data) = predicate.kind().skip_binder() {
+ if set.insert(data.def_id()) {
+ stack.push(data.def_id());
+ }
+ }
+ }
+
+ Some(trait_did)
+ })
+ }
+
+ /// Given a closure signature, returns an equivalent fn 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 signature. 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 signature_unclosure(
+ self,
+ sig: PolyFnSig<'tcx>,
+ unsafety: hir::Unsafety,
+ ) -> PolyFnSig<'tcx> {
+ sig.map_bound(|s| {
+ let params_iter = match s.inputs()[0].kind() {
+ ty::Tuple(params) => params.into_iter(),
+ _ => bug!(),
+ };
+ self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust)
+ })
+ }
+
+ /// Same a `self.mk_region(kind)`, but avoids accessing the interners if
+ /// `*r == kind`.
+ #[inline]
+ pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
+ if *r == kind { r } else { self.mk_region(kind) }
+ }
+
+ #[allow(rustc::usage_of_ty_tykind)]
+ #[inline]
+ pub fn mk_ty(self, st: TyKind<'tcx>) -> Ty<'tcx> {
+ self.interners.intern_ty(
+ st,
+ self.sess,
+ &self.definitions.read(),
+ &*self.cstore,
+ // This is only used to create a stable hashing context.
+ &self.untracked_resolutions.source_span,
+ )
+ }
+
+ #[inline]
+ pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
+ self.interners.intern_predicate(binder)
+ }
+
+ #[inline]
+ pub fn reuse_or_mk_predicate(
+ self,
+ pred: Predicate<'tcx>,
+ binder: Binder<'tcx, PredicateKind<'tcx>>,
+ ) -> Predicate<'tcx> {
+ if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
+ }
+
+ pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> {
+ match tm {
+ IntTy::Isize => self.types.isize,
+ IntTy::I8 => self.types.i8,
+ IntTy::I16 => self.types.i16,
+ IntTy::I32 => self.types.i32,
+ IntTy::I64 => self.types.i64,
+ IntTy::I128 => self.types.i128,
+ }
+ }
+
+ pub fn mk_mach_uint(self, tm: UintTy) -> Ty<'tcx> {
+ match tm {
+ UintTy::Usize => self.types.usize,
+ UintTy::U8 => self.types.u8,
+ UintTy::U16 => self.types.u16,
+ UintTy::U32 => self.types.u32,
+ UintTy::U64 => self.types.u64,
+ UintTy::U128 => self.types.u128,
+ }
+ }
+
+ pub fn mk_mach_float(self, tm: FloatTy) -> Ty<'tcx> {
+ match tm {
+ FloatTy::F32 => self.types.f32,
+ FloatTy::F64 => self.types.f64,
+ }
+ }
+
+ #[inline]
+ pub fn mk_static_str(self) -> Ty<'tcx> {
+ self.mk_imm_ref(self.lifetimes.re_static, self.types.str_)
+ }
+
+ #[inline]
+ pub fn mk_adt(self, def: AdtDef<'tcx>, 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.bound_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(LangItem::OwnedBox, None);
+ self.mk_generic_adt(def_id, ty)
+ }
+
+ #[inline]
+ pub fn mk_lang_item(self, ty: Ty<'tcx>, item: 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_diagnostic_item(self, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> {
+ let def_id = self.get_diagnostic_item(name)?;
+ 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(LangItem::MaybeUninit, 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, 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, mutbl: hir::Mutability::Not })
+ }
+
+ #[inline]
+ pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Mut })
+ }
+
+ #[inline]
+ pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Not })
+ }
+
+ #[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> {
+ self.mk_ty(Tuple(self.intern_type_list(&ts)))
+ }
+
+ pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output {
+ iter.intern_with(|ts| self.mk_ty(Tuple(self.intern_type_list(&ts))))
+ }
+
+ #[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_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: &'tcx List<ty::Binder<'tcx, 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, &'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>) -> Const<'tcx> {
+ self.mk_const(ty::ConstS { kind: 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>) -> ty::Const<'tcx> {
+ self.mk_const(ty::ConstS { kind: 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 }))
+ }
+
+ #[inline]
+ pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> Const<'tcx> {
+ self.mk_const(ty::ConstS { kind: 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: AdtDef<'tcx>,
+ variant_index: VariantIdx,
+ ) -> Place<'tcx> {
+ self.mk_place_elem(
+ place,
+ PlaceElem::Downcast(Some(adt_def.variant(variant_index).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_poly_existential_predicates(
+ self,
+ eps: &[ty::Binder<'tcx, ExistentialPredicate<'tcx>>],
+ ) -> &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> {
+ assert!(!eps.is_empty());
+ assert!(
+ eps.array_windows()
+ .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder())
+ != Ordering::Greater)
+ );
+ self._intern_poly_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.is_empty() {
+ // 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.is_empty() {
+ List::empty()
+ } else {
+ // Actually intern type lists as lists of `GenericArg`s.
+ //
+ // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound
+ // as explained in ty_slice_as_generic_arg`. With this,
+ // we guarantee that even when transmuting between `List<Ty<'tcx>>`
+ // and `List<GenericArg<'tcx>>`, the uniqueness requirement for
+ // lists is upheld.
+ let substs = self._intern_substs(ty::subst::ty_slice_as_generic_args(ts));
+ substs.try_as_type_list().unwrap()
+ }
+ }
+
+ pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List<GenericArg<'tcx>> {
+ if ts.is_empty() { List::empty() } else { self._intern_substs(ts) }
+ }
+
+ pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List<ProjectionKind> {
+ if ps.is_empty() { List::empty() } else { self._intern_projs(ps) }
+ }
+
+ pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> {
+ if ts.is_empty() { List::empty() } else { self._intern_place_elems(ts) }
+ }
+
+ pub fn intern_canonical_var_infos(
+ self,
+ ts: &[CanonicalVarInfo<'tcx>],
+ ) -> CanonicalVarInfos<'tcx> {
+ if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) }
+ }
+
+ pub fn intern_bound_variable_kinds(
+ self,
+ ts: &[ty::BoundVariableKind],
+ ) -> &'tcx List<ty::BoundVariableKind> {
+ if ts.is_empty() { List::empty() } else { self._intern_bound_variable_kinds(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_poly_existential_predicates<
+ I: InternAs<
+ [ty::Binder<'tcx, ExistentialPredicate<'tcx>>],
+ &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>,
+ >,
+ >(
+ self,
+ iter: I,
+ ) -> I::Output {
+ iter.intern_with(|xs| self.intern_poly_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_bound_variable_kinds<
+ I: InternAs<[ty::BoundVariableKind], &'tcx List<ty::BoundVariableKind>>,
+ >(
+ self,
+ iter: I,
+ ) -> I::Output {
+ iter.intern_with(|xs| self.intern_bound_variable_kinds(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_attr(attr).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, LintLevelSource) {
+ let sets = self.lint_levels(());
+ 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;
+ }
+ }
+
+ /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
+ /// typically generated by `#[derive(LintDiagnostic)]`).
+ pub fn emit_spanned_lint(
+ self,
+ lint: &'static Lint,
+ hir_id: HirId,
+ span: impl Into<MultiSpan>,
+ decorator: impl for<'a> DecorateLint<'a, ()>,
+ ) {
+ self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag))
+ }
+
+ 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);
+ }
+
+ /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
+ /// generated by `#[derive(LintDiagnostic)]`).
+ pub fn emit_lint(
+ self,
+ lint: &'static Lint,
+ id: HirId,
+ decorator: impl for<'a> DecorateLint<'a, ()>,
+ ) {
+ self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag))
+ }
+
+ 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 [TraitCandidate]> {
+ let map = self.in_scope_traits_map(id.owner)?;
+ let candidates = map.get(&id.local_id)?;
+ Some(&*candidates)
+ }
+
+ pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
+ debug!(?id, "named_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_or(false, |set| {
+ let def_id = self.hir().local_def_id(id);
+ set.contains(&def_id)
+ })
+ }
+
+ pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
+ self.mk_bound_variable_kinds(
+ self.late_bound_vars_map(id.owner)
+ .and_then(|map| map.get(&id.local_id).cloned())
+ .unwrap_or_else(|| {
+ bug!("No bound vars found for {:?} ({:?})", self.hir().node_to_string(id), id)
+ })
+ .iter(),
+ )
+ }
+
+ /// Whether the `def_id` counts as const fn in the current crate, considering all active
+ /// feature gates
+ pub fn is_const_fn(self, def_id: DefId) -> bool {
+ if self.is_const_fn_raw(def_id) {
+ match self.lookup_const_stability(def_id) {
+ Some(stability) if stability.is_const_unstable() => {
+ // has a `rustc_const_unstable` attribute, check whether the user enabled the
+ // corresponding feature gate.
+ self.features()
+ .declared_lib_features
+ .iter()
+ .any(|&(sym, _)| sym == stability.feature)
+ }
+ // functions without const stability are either stable user written
+ // const fn or the user is using feature gates and we thus don't
+ // care what they do
+ _ => true,
+ }
+ } else {
+ false
+ }
+ }
+
+ /// Whether the trait impl is marked const. This does not consider stability or feature gates.
+ pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
+ let Some(local_def_id) = def_id.as_local() else { return false };
+ let hir_id = self.local_def_id_to_hir_id(local_def_id);
+ let node = self.hir().get(hir_id);
+
+ matches!(
+ node,
+ hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
+ ..
+ })
+ )
+ }
+}
+
+impl<'tcx> TyCtxtAt<'tcx> {
+ /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
+ #[track_caller]
+ pub fn ty_error(self) -> Ty<'tcx> {
+ self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported")
+ }
+
+ /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
+ /// ensure it gets used.
+ #[track_caller]
+ pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> {
+ self.tcx.ty_error_with_message(self.span, msg)
+ }
+}
+
+// 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.resolutions = |tcx, ()| &tcx.untracked_resolutions;
+ providers.resolver_for_lowering = |tcx, ()| &tcx.untracked_resolver_for_lowering;
+ providers.module_reexports =
+ |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
+ providers.crate_name = |tcx, id| {
+ assert_eq!(id, LOCAL_CRATE);
+ tcx.crate_name
+ };
+ providers.maybe_unused_trait_imports =
+ |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
+ providers.maybe_unused_extern_crates =
+ |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..];
+ providers.names_imported_by_glob_use = |tcx, id| {
+ tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
+ };
+
+ providers.extern_mod_stmt_cnum =
+ |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
+ providers.output_filenames = |tcx, ()| &tcx.output_filenames;
+ providers.features_query = |tcx, ()| tcx.sess.features_untracked();
+ providers.is_panic_runtime = |tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
+ };
+ providers.is_compiler_builtins = |tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ tcx.sess.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/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
new file mode 100644
index 000000000..dd2f43210
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -0,0 +1,501 @@
+//! Diagnostics related methods for `Ty`.
+
+use std::ops::ControlFlow;
+
+use crate::ty::{
+ visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy,
+ PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
+};
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::WherePredicate;
+use rustc_span::Span;
+use rustc_type_ir::sty::TyKind::*;
+
+impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ format!("{}", self).into_diagnostic_arg()
+ }
+}
+
+impl<'tcx> Ty<'tcx> {
+ /// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive.
+ pub fn is_primitive_ty(self) -> bool {
+ matches!(
+ self.kind(),
+ Bool | Char
+ | Str
+ | Int(_)
+ | Uint(_)
+ | Float(_)
+ | Infer(
+ InferTy::IntVar(_)
+ | InferTy::FloatVar(_)
+ | InferTy::FreshIntTy(_)
+ | InferTy::FreshFloatTy(_)
+ )
+ )
+ }
+
+ /// 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(_)
+ | InferTy::FloatVar(_)
+ | InferTy::FreshIntTy(_)
+ | 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.non_erasable_generics().next().is_none(),
+ Ref(_, ty, _) => ty.is_simple_text(),
+ _ => self.is_simple_ty(),
+ }
+ }
+}
+
+pub trait IsSuggestable<'tcx> {
+ /// Whether this makes sense to suggest in a diagnostic.
+ ///
+ /// We filter out certain types and constants since they don't provide
+ /// meaningful rendered suggestions when pretty-printed. We leave some
+ /// nonsense, such as region vars, since those render as `'_` and are
+ /// usually okay to reinterpret as elided lifetimes.
+ ///
+ /// Only if `infer_suggestable` is true, we consider type and const
+ /// inference variables to be suggestable.
+ fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
+}
+
+impl<'tcx, T> IsSuggestable<'tcx> for T
+where
+ T: TypeVisitable<'tcx>,
+{
+ fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
+ self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
+ }
+}
+
+pub fn suggest_arbitrary_trait_bound<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ generics: &hir::Generics<'_>,
+ err: &mut Diagnostic,
+ trait_pred: PolyTraitPredicate<'tcx>,
+) -> bool {
+ if !trait_pred.is_suggestable(tcx, false) {
+ return false;
+ }
+
+ let param_name = trait_pred.skip_binder().self_ty().to_string();
+ let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
+ let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+
+ // Skip, there is a param named Self
+ if param.is_some() && param_name == "Self" {
+ return false;
+ }
+
+ // Suggest a where clause bound for a non-type parameter.
+ err.span_suggestion_verbose(
+ generics.tail_span_for_predicate_suggestion(),
+ &format!(
+ "consider {} `where` clause, but there might be an alternative better way to express \
+ this requirement",
+ if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" },
+ ),
+ format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint),
+ Applicability::MaybeIncorrect,
+ );
+ true
+}
+
+#[derive(Debug)]
+enum SuggestChangingConstraintsMessage<'a> {
+ RestrictBoundFurther,
+ RestrictType { ty: &'a str },
+ RestrictTypeFurther { ty: &'a str },
+ RemovingQSized,
+}
+
+fn suggest_removing_unsized_bound(
+ tcx: TyCtxt<'_>,
+ generics: &hir::Generics<'_>,
+ suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
+ param: &hir::GenericParam<'_>,
+ def_id: Option<DefId>,
+) {
+ // See if there's a `?Sized` bound that can be removed to suggest that.
+ // First look at the `where` clause because we can have `where T: ?Sized`,
+ // then look at params.
+ let param_def_id = tcx.hir().local_def_id(param.hir_id);
+ for (where_pos, predicate) in generics.predicates.iter().enumerate() {
+ let WherePredicate::BoundPredicate(predicate) = predicate else {
+ continue;
+ };
+ if !predicate.is_param_bound(param_def_id.to_def_id()) {
+ continue;
+ };
+
+ for (pos, bound) in predicate.bounds.iter().enumerate() {
+ let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
+ continue;
+ };
+ if poly.trait_ref.trait_def_id() != def_id {
+ continue;
+ }
+ let sp = generics.span_for_bound_removal(where_pos, pos);
+ suggestions.push((
+ sp,
+ String::new(),
+ SuggestChangingConstraintsMessage::RemovingQSized,
+ ));
+ }
+ }
+}
+
+/// Suggest restricting a type param with a new bound.
+pub fn suggest_constraining_type_param(
+ tcx: TyCtxt<'_>,
+ generics: &hir::Generics<'_>,
+ err: &mut Diagnostic,
+ param_name: &str,
+ constraint: &str,
+ def_id: Option<DefId>,
+) -> bool {
+ suggest_constraining_type_params(
+ tcx,
+ generics,
+ err,
+ [(param_name, constraint, def_id)].into_iter(),
+ )
+}
+
+/// Suggest restricting a type param with a new bound.
+pub fn suggest_constraining_type_params<'a>(
+ tcx: TyCtxt<'_>,
+ generics: &hir::Generics<'_>,
+ err: &mut Diagnostic,
+ param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>,
+) -> bool {
+ let mut grouped = FxHashMap::default();
+ param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
+ grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id))
+ });
+
+ let mut applicability = Applicability::MachineApplicable;
+ let mut suggestions = Vec::new();
+
+ for (param_name, mut constraints) in grouped {
+ let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+ let Some(param) = param else { return false };
+
+ {
+ let mut sized_constraints =
+ constraints.drain_filter(|(_, def_id)| *def_id == tcx.lang_items().sized_trait());
+ if let Some((constraint, def_id)) = sized_constraints.next() {
+ applicability = Applicability::MaybeIncorrect;
+
+ err.span_label(
+ param.span,
+ &format!("this type parameter needs to be `{}`", constraint),
+ );
+ suggest_removing_unsized_bound(tcx, generics, &mut suggestions, param, def_id);
+ }
+ }
+
+ if constraints.is_empty() {
+ continue;
+ }
+
+ let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
+ constraint.sort();
+ constraint.dedup();
+ let constraint = constraint.join(" + ");
+ let mut suggest_restrict = |span, bound_list_non_empty| {
+ suggestions.push((
+ span,
+ if bound_list_non_empty {
+ format!(" + {}", constraint)
+ } else {
+ format!(" {}", constraint)
+ },
+ SuggestChangingConstraintsMessage::RestrictBoundFurther,
+ ))
+ };
+
+ // When the type parameter has been provided bounds
+ //
+ // Message:
+ // fn foo<T>(t: T) where T: Foo { ... }
+ // ^^^^^^
+ // |
+ // help: consider further restricting this bound with `+ Bar`
+ //
+ // Suggestion:
+ // fn foo<T>(t: T) where T: Foo { ... }
+ // ^
+ // |
+ // replace with: ` + Bar`
+ //
+ // Or, if user has provided some bounds, suggest restricting them:
+ //
+ // fn foo<T: Foo>(t: T) { ... }
+ // ---
+ // |
+ // help: consider further restricting this bound with `+ Bar`
+ //
+ // Suggestion for tools in this case is:
+ //
+ // fn foo<T: Foo>(t: T) { ... }
+ // --
+ // |
+ // replace with: `T: Bar +`
+ let param_def_id = tcx.hir().local_def_id(param.hir_id);
+ if let Some(span) = generics.bounds_span_for_suggestions(param_def_id) {
+ suggest_restrict(span, true);
+ continue;
+ }
+
+ if generics.has_where_clause_predicates {
+ // This part is a bit tricky, because using the `where` clause user can
+ // provide zero, one or many bounds for the same type parameter, so we
+ // have following cases to consider:
+ //
+ // When the type parameter has been provided zero bounds
+ //
+ // Message:
+ // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
+ // - help: consider restricting this type parameter with `where X: Bar`
+ //
+ // Suggestion:
+ // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
+ // - insert: `, X: Bar`
+ suggestions.push((
+ generics.tail_span_for_predicate_suggestion(),
+ constraints
+ .iter()
+ .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
+ .collect::<String>(),
+ SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
+ ));
+ continue;
+ }
+
+ // Additionally, there may be no `where` clause but the generic parameter has a default:
+ //
+ // Message:
+ // trait Foo<T=()> {... }
+ // - help: consider further restricting this type parameter with `where T: Zar`
+ //
+ // Suggestion:
+ // trait Foo<T=()> {... }
+ // - insert: `where T: Zar`
+ if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) {
+ // Suggest a bound, but there is no existing `where` clause *and* the type param has a
+ // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
+ suggestions.push((
+ generics.tail_span_for_predicate_suggestion(),
+ format!(" where {}: {}", param_name, constraint),
+ SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
+ ));
+ continue;
+ }
+
+ // If user has provided a colon, don't suggest adding another:
+ //
+ // fn foo<T:>(t: T) { ... }
+ // - insert: consider restricting this type parameter with `T: Foo`
+ if let Some(colon_span) = param.colon_span {
+ suggestions.push((
+ colon_span.shrink_to_hi(),
+ format!(" {}", constraint),
+ SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
+ ));
+ continue;
+ }
+
+ // If user hasn't provided any bounds, suggest adding a new one:
+ //
+ // fn foo<T>(t: T) { ... }
+ // - help: consider restricting this type parameter with `T: Foo`
+ suggestions.push((
+ param.span.shrink_to_hi(),
+ format!(": {}", constraint),
+ SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
+ ));
+ }
+
+ if suggestions.len() == 1 {
+ let (span, suggestion, msg) = suggestions.pop().unwrap();
+
+ let s;
+ let msg = match msg {
+ SuggestChangingConstraintsMessage::RestrictBoundFurther => {
+ "consider further restricting this bound"
+ }
+ SuggestChangingConstraintsMessage::RestrictType { ty } => {
+ s = format!("consider restricting type parameter `{}`", ty);
+ &s
+ }
+ SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
+ s = format!("consider further restricting type parameter `{}`", ty);
+ &s
+ }
+ SuggestChangingConstraintsMessage::RemovingQSized => {
+ "consider removing the `?Sized` bound to make the type parameter `Sized`"
+ }
+ };
+
+ err.span_suggestion_verbose(span, msg, suggestion, applicability);
+ } else if suggestions.len() > 1 {
+ err.multipart_suggestion_verbose(
+ "consider restricting type parameters",
+ suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(),
+ applicability,
+ );
+ }
+
+ true
+}
+
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
+
+impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
+ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+ match ty.kind {
+ hir::TyKind::TraitObject(
+ _,
+ hir::Lifetime {
+ name:
+ hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+ ..
+ },
+ _,
+ ) => {
+ self.0.push(ty);
+ }
+ hir::TyKind::OpaqueDef(item_id, _) => {
+ self.0.push(ty);
+ let item = self.1.item(item_id);
+ hir::intravisit::walk_item(self, item);
+ }
+ _ => {}
+ }
+ hir::intravisit::walk_ty(self, ty);
+ }
+}
+
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
+
+impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
+ fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
+ if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
+ lt.name
+ {
+ self.0.push(lt.span);
+ }
+ }
+}
+
+pub struct IsSuggestableVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ infer_suggestable: bool,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
+
+ FnDef(..)
+ | Closure(..)
+ | Infer(..)
+ | Generator(..)
+ | GeneratorWitness(..)
+ | Bound(_, _)
+ | Placeholder(_)
+ | Error(_) => {
+ return ControlFlow::Break(());
+ }
+
+ Opaque(did, _) => {
+ let parent = self.tcx.parent(*did);
+ if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
+ && let Opaque(parent_did, _) = self.tcx.type_of(parent).kind()
+ && parent_did == did
+ {
+ // Okay
+ } else {
+ return ControlFlow::Break(());
+ }
+ }
+
+ Dynamic(dty, _) => {
+ for pred in *dty {
+ match pred.skip_binder() {
+ ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
+ // Okay
+ }
+ _ => return ControlFlow::Break(()),
+ }
+ }
+ }
+
+ Param(param) => {
+ // FIXME: It would be nice to make this not use string manipulation,
+ // but it's pretty hard to do this, since `ty::ParamTy` is missing
+ // sufficient info to determine if it is synthetic, and we don't
+ // always have a convenient way of getting `ty::Generics` at the call
+ // sites we invoke `IsSuggestable::is_suggestable`.
+ if param.name.as_str().starts_with("impl ") {
+ return ControlFlow::Break(());
+ }
+ }
+
+ _ => {}
+ }
+
+ t.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match c.kind() {
+ ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
+
+ ConstKind::Infer(..)
+ | ConstKind::Bound(..)
+ | ConstKind::Placeholder(..)
+ | ConstKind::Error(..) => {
+ return ControlFlow::Break(());
+ }
+ _ => {}
+ }
+
+ c.super_visit_with(self)
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
new file mode 100644
index 000000000..3226950e7
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -0,0 +1,74 @@
+use crate::mir;
+use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use crate::ty::visit::TypeVisitable;
+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;
+ }
+ debug!("erase_regions({:?})", value);
+ let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
+ debug!("erase_regions = {:?}", value1);
+ value1
+ }
+}
+
+struct RegionEraserVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> 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.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
+ }
+
+ fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ let u = self.tcx.anonymize_bound_vars(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,
+ }
+ }
+
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ c.super_fold_with(self)
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
new file mode 100644
index 000000000..4b0bc3c11
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -0,0 +1,965 @@
+use crate::traits::{ObligationCause, ObligationCauseCode};
+use crate::ty::diagnostics::suggest_constraining_type_param;
+use crate::ty::print::{FmtPrinter, Printer};
+use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
+use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
+use rustc_errors::{pluralize, Diagnostic, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::{BytePos, Span};
+use rustc_target::spec::abi;
+
+use std::borrow::Cow;
+use std::fmt;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
+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, TypeVisitable)]
+pub enum TypeError<'tcx> {
+ Mismatch,
+ ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
+ PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
+ UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
+ AbiMismatch(ExpectedFound<abi::Abi>),
+ Mutability,
+ ArgumentMutability(usize),
+ TupleSize(ExpectedFound<usize>),
+ FixedArraySize(ExpectedFound<u64>),
+ ArgCount,
+ FieldMisMatch(Symbol, Symbol),
+
+ RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
+ RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
+ RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>),
+ RegionsPlaceholderMismatch,
+
+ Sorts(ExpectedFound<Ty<'tcx>>),
+ ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
+ IntMismatch(ExpectedFound<ty::IntVarValue>),
+ FloatMismatch(ExpectedFound<ty::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>),
+ CyclicConst(ty::Const<'tcx>),
+ ProjectionMismatched(ExpectedFound<DefId>),
+ ExistentialMismatch(
+ ExpectedFound<&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>>,
+ ),
+ ObjectUnsafeCoercion(DefId),
+ ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
+
+ IntrinsicCast,
+ /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
+ TargetFeatureCast(DefId),
+}
+
+/// 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::BoundRegionKind| match br {
+ ty::BrNamed(_, name) => format!(" {}", name),
+ _ => String::new(),
+ };
+
+ match *self {
+ CyclicTy(_) => write!(f, "cyclic type of infinite size"),
+ CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
+ Mismatch => write!(f, "types differ"),
+ ConstnessMismatch(values) => {
+ write!(f, "expected {} bound, found {} bound", values.expected, values.found)
+ }
+ PolarityMismatch(values) => {
+ write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
+ }
+ UnsafetyMismatch(values) => {
+ write!(f, "expected {} fn, found {} fn", values.expected, values.found)
+ }
+ AbiMismatch(values) => {
+ write!(f, "expected {} fn, found {} fn", values.expected, values.found)
+ }
+ ArgumentMutability(_) | 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"),
+ FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
+ RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
+ // Actually naming the region here is a bit confusing because context is lacking
+ RegionsInsufficientlyPolymorphic(..) => {
+ write!(f, "one type is more general than the other")
+ }
+ 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"),
+ ArgumentSorts(values, _) | 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) => {
+ let expected = match values.expected {
+ ty::IntVarValue::IntType(ty) => ty.name_str(),
+ ty::IntVarValue::UintType(ty) => ty.name_str(),
+ };
+ let found = match values.found {
+ ty::IntVarValue::IntType(ty) => ty.name_str(),
+ ty::IntVarValue::UintType(ty) => ty.name_str(),
+ };
+ write!(f, "expected `{}`, found `{}`", expected, found)
+ }
+ FloatMismatch(ref values) => {
+ write!(
+ f,
+ "expected `{}`, found `{}`",
+ values.expected.name_str(),
+ values.found.name_str()
+ )
+ }
+ 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)
+ )
+ }),
+ 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"),
+ TargetFeatureCast(_) => write!(
+ f,
+ "cannot coerce functions with `#[target_feature]` to safe 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(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
+ | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
+ | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
+ | VariadicMismatch(_) | TargetFeatureCast(_) => false,
+
+ Mutability
+ | ArgumentMutability(_)
+ | TupleSize(_)
+ | ArgCount
+ | FieldMisMatch(..)
+ | RegionsDoesNotOutlive(..)
+ | RegionsInsufficientlyPolymorphic(..)
+ | RegionsOverlyPolymorphic(..)
+ | RegionsPlaceholderMismatch
+ | Traits(_)
+ | ProjectionMismatched(_)
+ | ExistentialMismatch(_)
+ | ConstMismatch(_)
+ | IntrinsicCast
+ | ObjectUnsafeCoercion(_) => true,
+ }
+ }
+}
+
+impl<'tcx> Ty<'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) => {
+ if t.is_simple_ty() {
+ return format!("array `{}`", self).into();
+ }
+
+ let n = tcx.lift(n).unwrap();
+ if let ty::ConstKind::Value(v) = n.kind() {
+ if let Some(n) = v.try_to_machine_usize(tcx) {
+ return format!("array of {} element{}", n, pluralize!(n)).into();
+ }
+ }
+ "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()
+ }
+ ty::Dynamic(..) => "trait object".into(),
+ ty::Closure(..) => "closure".into(),
+ ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().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::Param(p) => format!("type parameter `{}`", p).into(),
+ ty::Opaque(..) => "opaque type".into(),
+ ty::Error(_) => "type error".into(),
+ }
+ }
+
+ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> 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(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().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::Param(_) => "type parameter".into(),
+ ty::Opaque(..) => "opaque type".into(),
+ }
+ }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn note_and_explain_type_err(
+ self,
+ diag: &mut Diagnostic,
+ err: &TypeError<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ sp: Span,
+ body_owner_def_id: DefId,
+ ) {
+ use self::TypeError::*;
+ debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
+ match err {
+ ArgumentSorts(values, _) | Sorts(values) => {
+ match (values.expected.kind(), values.found.kind()) {
+ (ty::Closure(..), ty::Closure(..)) => {
+ diag.note("no two closures, even if identical, have the same type");
+ diag.help("consider boxing your closure and/or using it as a trait object");
+ }
+ (ty::Opaque(..), ty::Opaque(..)) => {
+ // Issue #63167
+ diag.note("distinct uses of `impl Trait` result in different opaque types");
+ }
+ (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 == '_') {
+ diag.span_suggestion(
+ sp,
+ "use a float literal",
+ format!("{}.0", snippet),
+ 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) {
+ diag.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) {
+ diag.span_label(f_span, "found type parameter");
+ }
+ diag.note(
+ "a type parameter was expected, but a different one was found; \
+ you might be missing a type parameter or trait bound",
+ );
+ diag.note(
+ "for more information, visit \
+ https://doc.rust-lang.org/book/ch10-02-traits.html\
+ #traits-as-parameters",
+ );
+ }
+ (ty::Projection(_), ty::Projection(_)) => {
+ diag.note("an associated type was expected, but a different one was found");
+ }
+ (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), 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) {
+ diag.span_label(p_span, "this type parameter");
+ }
+ let hir = self.hir();
+ let mut note = true;
+ if let Some(generics) = generics
+ .type_param(p, self)
+ .def_id
+ .as_local()
+ .map(|id| hir.local_def_id_to_hir_id(id))
+ .and_then(|id| self.hir().find(self.hir().get_parent_node(id)))
+ .as_ref()
+ .and_then(|node| node.generics())
+ {
+ // Synthesize the associated type restriction `Add<Output = Expected>`.
+ // FIXME: extract this logic for use in other diagnostics.
+ let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
+ let path =
+ self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
+ let item_name = self.item_name(proj.item_def_id);
+ let item_args = self.format_generic_args(assoc_substs);
+
+ let path = if path.ends_with('>') {
+ format!(
+ "{}, {}{} = {}>",
+ &path[..path.len() - 1],
+ item_name,
+ item_args,
+ p
+ )
+ } else {
+ format!("{}<{}{} = {}>", path, item_name, item_args, p)
+ };
+ note = !suggest_constraining_type_param(
+ self,
+ generics,
+ diag,
+ &format!("{}", proj.self_ty()),
+ &path,
+ None,
+ );
+ }
+ if note {
+ diag.note("you might be missing a type parameter or trait bound");
+ }
+ }
+ (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..))
+ | (ty::Dynamic(..) | ty::Opaque(..), 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) {
+ diag.span_label(p_span, "this type parameter");
+ }
+ diag.help("type parameters must be constrained to match other types");
+ if self.sess.teach(&diag.get_code().unwrap()) {
+ diag.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 }
+}
+```",
+ );
+ }
+ diag.note(
+ "for more information, visit \
+ https://doc.rust-lang.org/book/ch10-02-traits.html\
+ #traits-as-parameters",
+ );
+ }
+ (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
+ 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) {
+ diag.span_label(p_span, "this type parameter");
+ }
+ diag.help(&format!(
+ "every closure has a distinct type and so could not always match the \
+ caller-chosen type of parameter `{}`",
+ p
+ ));
+ }
+ (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) {
+ diag.span_label(p_span, "this type parameter");
+ }
+ }
+ (ty::Projection(proj_ty), _) => {
+ self.expected_projection(
+ diag,
+ proj_ty,
+ values,
+ body_owner_def_id,
+ cause.code(),
+ );
+ }
+ (_, ty::Projection(proj_ty)) => {
+ let msg = format!(
+ "consider constraining the associated type `{}` to `{}`",
+ values.found, values.expected,
+ );
+ if !(self.suggest_constraining_opaque_associated_type(
+ diag,
+ &msg,
+ proj_ty,
+ values.expected,
+ ) || self.suggest_constraint(
+ diag,
+ &msg,
+ body_owner_def_id,
+ proj_ty,
+ values.expected,
+ )) {
+ diag.help(&msg);
+ diag.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() {
+ diag.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",
+ );
+ }
+ }
+ TargetFeatureCast(def_id) => {
+ let target_spans =
+ self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span);
+ diag.note(
+ "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
+ );
+ diag.span_labels(target_spans, "`#[target_feature]` added here");
+ }
+ _ => {}
+ }
+ }
+
+ fn suggest_constraint(
+ self,
+ diag: &mut Diagnostic,
+ msg: &str,
+ body_owner_def_id: DefId,
+ proj_ty: &ty::ProjectionTy<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> bool {
+ let assoc = self.associated_item(proj_ty.item_def_id);
+ let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
+ if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
+ if let Some(hir_generics) = item.generics() {
+ // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
+ // This will also work for `impl Trait`.
+ let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
+ let generics = self.generics_of(body_owner_def_id);
+ generics.type_param(param_ty, self).def_id
+ } else {
+ return false;
+ };
+ let Some(def_id) = def_id.as_local() else {
+ return false;
+ };
+
+ // First look in the `where` clause, as this might be
+ // `fn foo<T>(x: T) where T: Trait`.
+ for pred in hir_generics.bounds_for_param(def_id) {
+ if self.constrain_generic_bound_associated_type_structured_suggestion(
+ diag,
+ &trait_ref,
+ pred.bounds,
+ &assoc,
+ assoc_substs,
+ ty,
+ msg,
+ false,
+ ) {
+ return true;
+ }
+ }
+ }
+ }
+ false
+ }
+
+ /// An associated type was expected and a different type was found.
+ ///
+ /// We perform a few different checks to see what we can suggest:
+ ///
+ /// - In the current item, look for associated functions that return the expected type and
+ /// suggest calling them. (Not a structured suggestion.)
+ /// - If any of the item's generic bounds can be constrained, we suggest constraining the
+ /// associated type to the found type.
+ /// - If the associated type has a default type and was expected inside of a `trait`, we
+ /// mention that this is disallowed.
+ /// - If all other things fail, and the error is not because of a mismatch between the `trait`
+ /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
+ /// fn that returns the type.
+ fn expected_projection(
+ self,
+ diag: &mut Diagnostic,
+ proj_ty: &ty::ProjectionTy<'tcx>,
+ values: &ExpectedFound<Ty<'tcx>>,
+ body_owner_def_id: DefId,
+ cause_code: &ObligationCauseCode<'_>,
+ ) {
+ let msg = format!(
+ "consider constraining the associated type `{}` to `{}`",
+ values.expected, values.found
+ );
+ let body_owner = self.hir().get_if_local(body_owner_def_id);
+ let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
+
+ // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
+ let callable_scope = matches!(
+ body_owner,
+ Some(
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+ | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+ | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
+ )
+ );
+ let impl_comparison =
+ matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
+ let assoc = self.associated_item(proj_ty.item_def_id);
+ if !callable_scope || impl_comparison {
+ // We do not want to suggest calling functions when the reason of the
+ // type error is a comparison of an `impl` with its `trait` or when the
+ // scope is outside of a `Body`.
+ } else {
+ // If we find a suitable associated function that returns the expected type, we don't
+ // want the more general suggestion later in this method about "consider constraining
+ // the associated type or calling a method that returns the associated type".
+ let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
+ diag,
+ assoc.container_id(self),
+ current_method_ident,
+ proj_ty.item_def_id,
+ values.expected,
+ );
+ // Possibly suggest constraining the associated type to conform to the
+ // found type.
+ if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
+ || point_at_assoc_fn
+ {
+ return;
+ }
+ }
+
+ self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
+
+ if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
+ return;
+ }
+
+ if !impl_comparison {
+ // Generic suggestion when we can't be more specific.
+ if callable_scope {
+ diag.help(&format!(
+ "{} or calling a method that returns `{}`",
+ msg, values.expected
+ ));
+ } else {
+ diag.help(&msg);
+ }
+ diag.note(
+ "for more information, visit \
+ https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+ );
+ }
+ if self.sess.teach(&diag.get_code().unwrap()) {
+ diag.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() }
+}
+```",
+ );
+ }
+ }
+
+ /// When the expected `impl Trait` is not defined in the current item, it will come from
+ /// a return type. This can occur when dealing with `TryStream` (#71035).
+ fn suggest_constraining_opaque_associated_type(
+ self,
+ diag: &mut Diagnostic,
+ msg: &str,
+ proj_ty: &ty::ProjectionTy<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> bool {
+ let assoc = self.associated_item(proj_ty.item_def_id);
+ if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
+ let opaque_local_def_id = def_id.as_local();
+ let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
+ match &self.hir().expect_item(opaque_local_def_id).kind {
+ hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+ _ => bug!("The HirId comes from a `ty::Opaque`"),
+ }
+ } else {
+ return false;
+ };
+
+ let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
+
+ self.constrain_generic_bound_associated_type_structured_suggestion(
+ diag,
+ &trait_ref,
+ opaque_hir_ty.bounds,
+ assoc,
+ assoc_substs,
+ ty,
+ msg,
+ true,
+ )
+ } else {
+ false
+ }
+ }
+
+ fn point_at_methods_that_satisfy_associated_type(
+ self,
+ diag: &mut Diagnostic,
+ assoc_container_id: DefId,
+ current_method_ident: Option<Symbol>,
+ proj_ty_item_def_id: DefId,
+ expected: Ty<'tcx>,
+ ) -> bool {
+ let items = self.associated_items(assoc_container_id);
+ // Find all the methods in the trait that could be called to construct the
+ // expected associated type.
+ // FIXME: consider suggesting the use of associated `const`s.
+ let methods: Vec<(Span, String)> = items
+ .items
+ .iter()
+ .filter(|(name, item)| {
+ ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident
+ })
+ .filter_map(|(_, item)| {
+ let method = self.fn_sig(item.def_id);
+ match *method.output().skip_binder().kind() {
+ ty::Projection(ty::ProjectionTy { item_def_id, .. })
+ if item_def_id == proj_ty_item_def_id =>
+ {
+ Some((
+ self.def_span(item.def_id),
+ format!("consider calling `{}`", self.def_path_str(item.def_id)),
+ ))
+ }
+ _ => None,
+ }
+ })
+ .collect();
+ if !methods.is_empty() {
+ // Use a single `help:` to show all the methods in the trait that can
+ // be used to construct the expected associated type.
+ let mut span: MultiSpan =
+ methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
+ let msg = format!(
+ "{some} method{s} {are} available that return{r} `{ty}`",
+ some = if methods.len() == 1 { "a" } else { "some" },
+ s = pluralize!(methods.len()),
+ are = pluralize!("is", methods.len()),
+ r = if methods.len() == 1 { "s" } else { "" },
+ ty = expected
+ );
+ for (sp, label) in methods.into_iter() {
+ span.push_span_label(sp, label);
+ }
+ diag.span_help(span, &msg);
+ return true;
+ }
+ false
+ }
+
+ fn point_at_associated_type(
+ self,
+ diag: &mut Diagnostic,
+ body_owner_def_id: DefId,
+ found: Ty<'tcx>,
+ ) -> bool {
+ let Some(hir_id) = body_owner_def_id.as_local() else {
+ return false;
+ };
+ let hir_id = self.hir().local_def_id_to_hir_id(hir_id);
+ // When `body_owner` is an `impl` or `trait` item, look in its associated types for
+ // `expected` and point at it.
+ let parent_id = self.hir().get_parent_item(hir_id);
+ let item = self.hir().find_by_def_id(parent_id);
+ debug!("expected_projection parent item {:?}", item);
+ match item {
+ Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
+ // FIXME: account for `#![feature(specialization)]`
+ for item in &items[..] {
+ match item.kind {
+ hir::AssocItemKind::Type => {
+ // FIXME: account for returning some type in a trait fn impl that has
+ // an assoc type as a return type (#72076).
+ if let hir::Defaultness::Default { has_value: true } =
+ self.impl_defaultness(item.id.def_id)
+ {
+ if self.type_of(item.id.def_id) == found {
+ diag.span_label(
+ item.span,
+ "associated type defaults can't be assumed inside the \
+ trait defining them",
+ );
+ return true;
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ Some(hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
+ ..
+ })) => {
+ for item in &items[..] {
+ if let hir::AssocItemKind::Type = item.kind {
+ if self.type_of(item.id.def_id) == found {
+ diag.span_label(item.span, "expected this associated type");
+ return true;
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ false
+ }
+
+ /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
+ /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+ ///
+ /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+ /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+ /// trait bound as the one we're looking for. This can help in cases where the associated
+ /// type is defined on a supertrait of the one present in the bounds.
+ fn constrain_generic_bound_associated_type_structured_suggestion(
+ self,
+ diag: &mut Diagnostic,
+ trait_ref: &ty::TraitRef<'tcx>,
+ bounds: hir::GenericBounds<'_>,
+ assoc: &ty::AssocItem,
+ assoc_substs: &[ty::GenericArg<'tcx>],
+ ty: Ty<'tcx>,
+ msg: &str,
+ is_bound_surely_present: bool,
+ ) -> bool {
+ // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
+
+ let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+ hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+ _ => None,
+ });
+
+ let matching_trait_bounds = trait_bounds
+ .clone()
+ .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+ .collect::<Vec<_>>();
+
+ let span = match &matching_trait_bounds[..] {
+ &[ptr] => ptr.span,
+ &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+ &[ptr] => ptr.span,
+ _ => return false,
+ },
+ _ => return false,
+ };
+
+ self.constrain_associated_type_structured_suggestion(
+ diag,
+ span,
+ assoc,
+ assoc_substs,
+ ty,
+ msg,
+ )
+ }
+
+ /// Given a span corresponding to a bound, provide a structured suggestion to set an
+ /// associated type to a given type `ty`.
+ fn constrain_associated_type_structured_suggestion(
+ self,
+ diag: &mut Diagnostic,
+ span: Span,
+ assoc: &ty::AssocItem,
+ assoc_substs: &[ty::GenericArg<'tcx>],
+ ty: Ty<'tcx>,
+ msg: &str,
+ ) -> bool {
+ if let Ok(has_params) =
+ self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
+ {
+ let (span, sugg) = if has_params {
+ let pos = span.hi() - BytePos(1);
+ let span = Span::new(pos, pos, span.ctxt(), span.parent());
+ (span, format!(", {} = {}", assoc.ident(self), ty))
+ } else {
+ let item_args = self.format_generic_args(assoc_substs);
+ (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
+ };
+ diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
+ return true;
+ }
+ false
+ }
+
+ fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
+ FmtPrinter::new(self, hir::def::Namespace::TypeNS)
+ .path_generic_args(Ok, args)
+ .expect("could not write to `String`.")
+ .into_buffer()
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
new file mode 100644
index 000000000..8d019a3ba
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -0,0 +1,405 @@
+use crate::mir::Mutability;
+use crate::ty::subst::GenericArgKind;
+use crate::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_hir::def_id::DefId;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::iter;
+
+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, TyEncodable, TyDecodable, HashStable)]
+pub enum SimplifiedTypeGen<D>
+where
+ D: Copy + Debug + Eq,
+{
+ BoolSimplifiedType,
+ CharSimplifiedType,
+ IntSimplifiedType(ty::IntTy),
+ UintSimplifiedType(ty::UintTy),
+ FloatSimplifiedType(ty::FloatTy),
+ AdtSimplifiedType(D),
+ ForeignSimplifiedType(D),
+ StrSimplifiedType,
+ ArraySimplifiedType,
+ SliceSimplifiedType,
+ RefSimplifiedType(Mutability),
+ PtrSimplifiedType(Mutability),
+ 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),
+ PlaceholderSimplifiedType,
+}
+
+/// Generic parameters are pretty much just bound variables, e.g.
+/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as
+/// `for<'a, T> fn(&'a T) -> u32`.
+///
+/// Typecheck of `foo` has to succeed for all possible generic arguments, so
+/// during typeck, we have to treat its generic parameters as if they
+/// were placeholders.
+///
+/// But when calling `foo` we only have to provide a specific generic argument.
+/// In that case the generic parameters are instantiated with inference variables.
+/// As we use `simplify_type` before that instantiation happens, we just treat
+/// generic parameters as if they were inference variables in that case.
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum TreatParams {
+ /// Treat parameters as placeholders in the given environment.
+ ///
+ /// Note that this also causes us to treat projections as if they were
+ /// placeholders. This is only correct if the given projection cannot
+ /// be normalized in the current context. Even if normalization fails,
+ /// it may still succeed later if the projection contains any inference
+ /// variables.
+ AsPlaceholder,
+ AsInfer,
+}
+
+/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
+///
+/// **This function should only be used if you need to store or retrieve the type from some
+/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt]
+/// instead.**
+///
+/// The idea is to get something simple that we can use to quickly decide if two types could unify,
+/// for example during method lookup. If this function returns `Some(x)` it can only unify with
+/// types for which this method returns either `Some(x)` as well or `None`.
+///
+/// A special case here are parameters and projections, which are only injective
+/// if they are treated as placeholders.
+///
+/// For example when storing impls based on their simplified self type, we treat
+/// generic parameters as if they were inference variables. We must not simplify them here,
+/// as they can unify with any other type.
+///
+/// With projections we have to be even more careful, as treating them as placeholders
+/// is only correct if they are fully normalized.
+///
+/// ¹ meaning that if the outermost layers are different, then the whole types are also different.
+pub fn simplify_type<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ treat_params: TreatParams,
+) -> 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(..) => Some(ArraySimplifiedType),
+ ty::Slice(..) => Some(SliceSimplifiedType),
+ ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)),
+ ty::Dynamic(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(_, _, mutbl) => Some(RefSimplifiedType(mutbl)),
+ ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
+ ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
+ ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())),
+ ty::Never => Some(NeverSimplifiedType),
+ ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())),
+ ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
+ ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
+ ty::Param(_) => match treat_params {
+ TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
+ TreatParams::AsInfer => None,
+ },
+ ty::Projection(_) => match treat_params {
+ // When treating `ty::Param` as a placeholder, projections also
+ // don't unify with anything else as long as they are fully normalized.
+ //
+ // We will have to be careful with lazy normalization here.
+ TreatParams::AsPlaceholder if !ty.has_infer_types_or_consts() => {
+ debug!("treating `{}` as a placeholder", ty);
+ Some(PlaceholderSimplifiedType)
+ }
+ TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
+ },
+ ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
+ ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
+ ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
+ }
+}
+
+impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
+ pub fn def(self) -> Option<D> {
+ match self {
+ AdtSimplifiedType(d)
+ | ForeignSimplifiedType(d)
+ | TraitSimplifiedType(d)
+ | ClosureSimplifiedType(d)
+ | GeneratorSimplifiedType(d)
+ | OpaqueSimplifiedType(d) => Some(d),
+ _ => None,
+ }
+ }
+
+ pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
+ where
+ F: Fn(D) -> U,
+ U: Copy + Debug + Eq,
+ {
+ match self {
+ BoolSimplifiedType => BoolSimplifiedType,
+ CharSimplifiedType => CharSimplifiedType,
+ IntSimplifiedType(t) => IntSimplifiedType(t),
+ UintSimplifiedType(t) => UintSimplifiedType(t),
+ FloatSimplifiedType(t) => FloatSimplifiedType(t),
+ AdtSimplifiedType(d) => AdtSimplifiedType(map(d)),
+ ForeignSimplifiedType(d) => ForeignSimplifiedType(map(d)),
+ StrSimplifiedType => StrSimplifiedType,
+ ArraySimplifiedType => ArraySimplifiedType,
+ SliceSimplifiedType => SliceSimplifiedType,
+ RefSimplifiedType(m) => RefSimplifiedType(m),
+ PtrSimplifiedType(m) => PtrSimplifiedType(m),
+ 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),
+ PlaceholderSimplifiedType => PlaceholderSimplifiedType,
+ }
+ }
+}
+
+/// Given generic arguments from an obligation and an impl,
+/// could these two be unified after replacing parameters in the
+/// the impl with inference variables.
+///
+/// For obligations, parameters won't be replaced by inference
+/// variables and only unify with themselves. We treat them
+/// the same way we treat placeholders.
+///
+/// We also use this function during coherence. For coherence the
+/// impls only have to overlap for some value, so we treat parameters
+/// on both sides like inference variables. This behavior is toggled
+/// using the `treat_obligation_params` field.
+#[derive(Debug, Clone, Copy)]
+pub struct DeepRejectCtxt {
+ pub treat_obligation_params: TreatParams,
+}
+
+impl DeepRejectCtxt {
+ pub fn generic_args_may_unify<'tcx>(
+ self,
+ obligation_arg: ty::GenericArg<'tcx>,
+ impl_arg: ty::GenericArg<'tcx>,
+ ) -> bool {
+ match (obligation_arg.unpack(), impl_arg.unpack()) {
+ // We don't fast reject based on regions for now.
+ (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
+ (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
+ self.types_may_unify(obl, imp)
+ }
+ (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
+ self.consts_may_unify(obl, imp)
+ }
+ _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"),
+ }
+ }
+
+ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
+ match impl_ty.kind() {
+ // Start by checking whether the type in the impl may unify with
+ // pretty much everything. Just return `true` in that case.
+ ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true,
+ // These types only unify with inference variables or their own
+ // variant.
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(..)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(..)
+ | ty::RawPtr(..)
+ | ty::Dynamic(..)
+ | ty::Ref(..)
+ | ty::Never
+ | ty::Tuple(..)
+ | ty::FnPtr(..)
+ | ty::Foreign(..)
+ | ty::Opaque(..) => {}
+ ty::FnDef(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Placeholder(..)
+ | ty::Bound(..)
+ | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"),
+ }
+
+ let k = impl_ty.kind();
+ match *obligation_ty.kind() {
+ // Purely rigid types, use structural equivalence.
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Never
+ | ty::Foreign(_) => obligation_ty == impl_ty,
+ ty::Ref(_, obl_ty, obl_mutbl) => match k {
+ &ty::Ref(_, impl_ty, impl_mutbl) => {
+ obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty)
+ }
+ _ => false,
+ },
+ ty::Adt(obl_def, obl_substs) => match k {
+ &ty::Adt(impl_def, impl_substs) => {
+ obl_def == impl_def
+ && iter::zip(obl_substs, impl_substs)
+ .all(|(obl, imp)| self.generic_args_may_unify(obl, imp))
+ }
+ _ => false,
+ },
+ ty::Slice(obl_ty) => {
+ matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
+ }
+ ty::Array(obl_ty, obl_len) => match k {
+ &ty::Array(impl_ty, impl_len) => {
+ self.types_may_unify(obl_ty, impl_ty)
+ && self.consts_may_unify(obl_len, impl_len)
+ }
+ _ => false,
+ },
+ ty::Tuple(obl) => match k {
+ &ty::Tuple(imp) => {
+ obl.len() == imp.len()
+ && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp))
+ }
+ _ => false,
+ },
+ ty::RawPtr(obl) => match k {
+ ty::RawPtr(imp) => obl.mutbl == imp.mutbl && self.types_may_unify(obl.ty, imp.ty),
+ _ => false,
+ },
+ ty::Dynamic(obl_preds, ..) => {
+ // Ideally we would walk the existential predicates here or at least
+ // compare their length. But considering that the relevant `Relate` impl
+ // actually sorts and deduplicates these, that doesn't work.
+ matches!(k, ty::Dynamic(impl_preds, ..) if
+ obl_preds.principal_def_id() == impl_preds.principal_def_id()
+ )
+ }
+ ty::FnPtr(obl_sig) => match k {
+ ty::FnPtr(impl_sig) => {
+ let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } =
+ obl_sig.skip_binder();
+ let impl_sig = impl_sig.skip_binder();
+
+ abi == impl_sig.abi
+ && c_variadic == impl_sig.c_variadic
+ && unsafety == impl_sig.unsafety
+ && inputs_and_output.len() == impl_sig.inputs_and_output.len()
+ && iter::zip(inputs_and_output, impl_sig.inputs_and_output)
+ .all(|(obl, imp)| self.types_may_unify(obl, imp))
+ }
+ _ => false,
+ },
+
+ // Opaque types in impls should be forbidden, but that doesn't
+ // stop compilation. So this match arm should never return true
+ // if compilation succeeds.
+ ty::Opaque(..) => matches!(k, ty::Opaque(..)),
+
+ // Impls cannot contain these types as these cannot be named directly.
+ ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false,
+
+ ty::Placeholder(..) => false,
+
+ // Depending on the value of `treat_obligation_params`, we either
+ // treat generic parameters like placeholders or like inference variables.
+ ty::Param(_) => match self.treat_obligation_params {
+ TreatParams::AsPlaceholder => false,
+ TreatParams::AsInfer => true,
+ },
+
+ ty::Infer(_) => true,
+
+ // As we're walking the whole type, it may encounter projections
+ // inside of binders and what not, so we're just going to assume that
+ // projections can unify with other stuff.
+ //
+ // Looking forward to lazy normalization this is the safer strategy anyways.
+ ty::Projection(_) => true,
+
+ ty::Error(_) => true,
+
+ ty::GeneratorWitness(..) | ty::Bound(..) => {
+ bug!("unexpected obligation type: {:?}", obligation_ty)
+ }
+ }
+ }
+
+ pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool {
+ match impl_ct.kind() {
+ ty::ConstKind::Param(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
+ return true;
+ }
+ ty::ConstKind::Value(_) => {}
+ ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+ bug!("unexpected impl arg: {:?}", impl_ct)
+ }
+ }
+
+ let k = impl_ct.kind();
+ match obligation_ct.kind() {
+ ty::ConstKind::Param(_) => match self.treat_obligation_params {
+ TreatParams::AsPlaceholder => false,
+ TreatParams::AsInfer => true,
+ },
+
+ // As we don't necessarily eagerly evaluate constants,
+ // they might unify with any value.
+ ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => true,
+ ty::ConstKind::Value(obl) => match k {
+ ty::ConstKind::Value(imp) => {
+ // FIXME(valtrees): Once we have valtrees, we can just
+ // compare them directly here.
+ match (obl.try_to_scalar_int(), imp.try_to_scalar_int()) {
+ (Some(obl), Some(imp)) => obl == imp,
+ _ => true,
+ }
+ }
+ _ => true,
+ },
+
+ ty::ConstKind::Infer(_) => true,
+
+ ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+ bug!("unexpected obl const: {:?}", obligation_ct)
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
new file mode 100644
index 000000000..ea6bb8a7a
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -0,0 +1,342 @@
+use crate::ty::subst::{GenericArg, GenericArgKind};
+use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
+use std::slice;
+
+#[derive(Debug)]
+pub struct FlagComputation {
+ pub flags: TypeFlags,
+
+ // see `Ty::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_predicate<'tcx>(binder: ty::Binder<'tcx, ty::PredicateKind<'_>>) -> FlagComputation {
+ let mut result = FlagComputation::new();
+ result.add_predicate(binder);
+ result
+ }
+
+ pub fn for_const(c: ty::Const<'_>) -> TypeFlags {
+ let mut result = FlagComputation::new();
+ result.add_const(c);
+ result.flags
+ }
+
+ pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags {
+ let mut result = FlagComputation::new();
+ result.add_unevaluated_const(uv);
+ result.flags
+ }
+
+ fn add_flags(&mut self, flags: TypeFlags) {
+ self.flags = self.flags | flags;
+ }
+
+ /// indicates that `self` refers to something at binding level `binder`
+ fn add_bound_var(&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 bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
+ where
+ F: FnOnce(&mut Self, T),
+ {
+ let mut computation = FlagComputation::new();
+
+ if !value.bound_vars().is_empty() {
+ computation.flags = computation.flags | TypeFlags::HAS_RE_LATE_BOUND;
+ }
+
+ f(&mut computation, value.skip_binder());
+
+ 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(..) => {}
+
+ &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
+
+ &ty::Param(_) => {
+ self.add_flags(TypeFlags::HAS_TY_PARAM);
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ }
+
+ &ty::Generator(_, ref substs, _) => {
+ let substs = substs.as_generator();
+ let should_remove_further_specializable =
+ !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_substs(substs.parent_substs());
+ if should_remove_further_specializable {
+ self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ }
+
+ self.add_ty(substs.resume_ty());
+ self.add_ty(substs.return_ty());
+ self.add_ty(substs.witness());
+ self.add_ty(substs.yield_ty());
+ self.add_ty(substs.tupled_upvars_ty());
+ }
+
+ &ty::GeneratorWitness(ts) => {
+ self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
+ }
+
+ &ty::Closure(_, substs) => {
+ let substs = substs.as_closure();
+ let should_remove_further_specializable =
+ !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_substs(substs.parent_substs());
+ if should_remove_further_specializable {
+ self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ }
+
+ self.add_ty(substs.sig_as_fn_ptr_ty());
+ self.add_ty(substs.kind_ty());
+ self.add_ty(substs.tupled_upvars_ty());
+ }
+
+ &ty::Bound(debruijn, _) => {
+ self.add_bound_var(debruijn);
+ }
+
+ &ty::Placeholder(..) => {
+ self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ }
+
+ &ty::Infer(infer) => {
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ match infer {
+ ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
+ self.add_flags(TypeFlags::HAS_TY_FRESH)
+ }
+
+ ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
+ self.add_flags(TypeFlags::HAS_TY_INFER)
+ }
+ }
+ }
+
+ &ty::Adt(_, substs) => {
+ self.add_substs(substs);
+ }
+
+ &ty::Projection(data) => {
+ self.add_flags(TypeFlags::HAS_TY_PROJECTION);
+ self.add_projection_ty(data);
+ }
+
+ &ty::Opaque(_, substs) => {
+ self.add_flags(TypeFlags::HAS_TY_OPAQUE);
+ self.add_substs(substs);
+ }
+
+ &ty::Dynamic(obj, r) => {
+ for predicate in obj.iter() {
+ self.bound_computation(predicate, |computation, predicate| match predicate {
+ ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
+ ty::ExistentialPredicate::Projection(p) => {
+ computation.add_existential_projection(&p);
+ }
+ ty::ExistentialPredicate::AutoTrait(_) => {}
+ });
+ }
+
+ 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(types) => {
+ self.add_tys(types);
+ }
+
+ &ty::FnDef(_, substs) => {
+ self.add_substs(substs);
+ }
+
+ &ty::FnPtr(fn_sig) => self.bound_computation(fn_sig, |computation, fn_sig| {
+ computation.add_tys(fn_sig.inputs());
+ computation.add_ty(fn_sig.output());
+ }),
+ }
+ }
+
+ fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
+ self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
+ }
+
+ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
+ match atom {
+ ty::PredicateKind::Trait(trait_pred) => {
+ self.add_substs(trait_pred.trait_ref.substs);
+ }
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
+ self.add_region(a);
+ self.add_region(b);
+ }
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, region)) => {
+ self.add_ty(ty);
+ self.add_region(region);
+ }
+ ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
+ self.add_ty(a);
+ self.add_ty(b);
+ }
+ ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+ self.add_ty(a);
+ self.add_ty(b);
+ }
+ ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+ self.add_projection_ty(projection_ty);
+ match term {
+ Term::Ty(ty) => self.add_ty(ty),
+ Term::Const(c) => self.add_const(c),
+ }
+ }
+ ty::PredicateKind::WellFormed(arg) => {
+ self.add_substs(slice::from_ref(&arg));
+ }
+ ty::PredicateKind::ObjectSafe(_def_id) => {}
+ ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
+ self.add_substs(substs);
+ }
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ self.add_unevaluated_const(uv);
+ }
+ ty::PredicateKind::ConstEquate(expected, found) => {
+ self.add_const(expected);
+ self.add_const(found);
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+ self.add_ty(ty);
+ }
+ }
+ }
+
+ 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_region(&mut self, r: ty::Region<'_>) {
+ self.add_flags(r.type_flags());
+ if let ty::ReLateBound(debruijn, _) = *r {
+ self.add_bound_var(debruijn);
+ }
+ }
+
+ fn add_const(&mut self, c: ty::Const<'_>) {
+ self.add_ty(c.ty());
+ match c.kind() {
+ ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
+ ty::ConstKind::Infer(infer) => {
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ match infer {
+ InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
+ InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
+ }
+ }
+ ty::ConstKind::Bound(debruijn, _) => {
+ self.add_bound_var(debruijn);
+ }
+ ty::ConstKind::Param(_) => {
+ self.add_flags(TypeFlags::HAS_CT_PARAM);
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ }
+ ty::ConstKind::Placeholder(_) => {
+ self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ }
+ ty::ConstKind::Value(_) => {}
+ ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
+ }
+ }
+
+ fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'_, P>) {
+ self.add_substs(ct.substs);
+ self.add_flags(TypeFlags::HAS_CT_PROJECTION);
+ }
+
+ fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
+ self.add_substs(projection.substs);
+ match projection.term {
+ ty::Term::Ty(ty) => self.add_ty(ty),
+ ty::Term::Const(ct) => self.add_const(ct),
+ }
+ }
+
+ fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
+ self.add_substs(projection_ty.substs);
+ }
+
+ fn add_substs(&mut self, substs: &[GenericArg<'_>]) {
+ 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/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
new file mode 100644
index 000000000..5e96e278b
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -0,0 +1,797 @@
+//! A folding traversal mechanism for complex data structures that contain type
+//! information.
+//!
+//! This is a modifying traversal. It consumes the data structure, producing a
+//! (possibly) modified version of it. Both fallible and infallible versions are
+//! available. The name is potentially confusing, because this traversal is more
+//! like `Iterator::map` than `Iterator::fold`.
+//!
+//! This traversal has limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! modification. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
+//!
+//! There are three groups of traits involved in each traversal.
+//! - `TypeFoldable`. This is implemented once for many types, including:
+//! - Types of interest, for which the the methods delegate to the
+//! folder.
+//! - All other types, including generic containers like `Vec` and `Option`.
+//! It defines a "skeleton" of how they should be folded.
+//! - `TypeSuperFoldable`. This is implemented only for each type of interest,
+//! and defines the folding "skeleton" for these types.
+//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each
+//! folder. This defines how types of interest are folded.
+//!
+//! This means each fold is a mixture of (a) generic folding operations, and (b)
+//! custom fold operations that are specific to the folder.
+//! - The `TypeFoldable` impls handle most of the traversal, and call into
+//! `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable`
+//! impl, because some of the types of interest are recursive and can contain
+//! other types of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable`
+//! impl, because each folder might provide custom handling only for some types
+//! of interest, or only for some variants of each type of interest, and then
+//! use default traversal for the remaining cases.
+//!
+//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
+//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so:
+//! ```text
+//! s.fold_with(folder) calls
+//! - ty.fold_with(folder) calls
+//! - folder.fold_ty(ty) may call
+//! - ty.super_fold_with(folder)
+//! - u.fold_with(folder)
+//! ```
+use crate::mir;
+use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable};
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_hir::def_id::DefId;
+
+use std::collections::BTreeMap;
+
+/// This trait is implemented for every type that can be folded,
+/// providing the skeleton of the traversal.
+///
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
+pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
+ /// The entry point for folding. To fold a value `t` with a folder `f`
+ /// call: `t.try_fold_with(f)`.
+ ///
+ /// For most types, this just traverses the value, calling `try_fold_with`
+ /// on each field/element.
+ ///
+ /// For types of interest (such as `Ty`), the implementation of method
+ /// calls a folder method specifically for that type (such as
+ /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
+ /// to `TypeFolder`.
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
+
+ /// A convenient alternative to `try_fold_with` for use with infallible
+ /// folders. Do not override this method, to ensure coherence with
+ /// `try_fold_with`.
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ self.try_fold_with(folder).into_ok()
+ }
+}
+
+// This trait is implemented for types of interest.
+pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
+ /// Provides a default fold for a type of interest. This should only be
+ /// called within `TypeFolder` methods, when a non-custom traversal is
+ /// desired for the value of the type of interest passed to that method.
+ /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
+ /// `ty.try_super_fold_with(self)`, but any other folding should be done
+ /// with `xyz.try_fold_with(self)`.
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error>;
+
+ /// A convenient alternative to `try_super_fold_with` for use with
+ /// infallible folders. Do not override this method, to ensure coherence
+ /// with `try_super_fold_with`.
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ self.try_super_fold_with(folder).into_ok()
+ }
+}
+
+/// This trait is implemented for every infallible folding traversal. There is
+/// a fold method defined for every type of interest. Each such method has a
+/// default that does an "identity" fold. Implementations of these methods
+/// often fall back to a `super_fold_with` method if the primary argument
+/// doesn't satisfy a particular condition.
+///
+/// A blanket implementation of [`FallibleTypeFolder`] will defer to
+/// the infallible methods of this trait to ensure that the two APIs
+/// are coherent.
+pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+
+ fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, 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: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ c.super_fold_with(self)
+ }
+
+ fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> {
+ uv.super_fold_with(self)
+ }
+
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ p.super_fold_with(self)
+ }
+
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ bug!("most type folders should not be folding MIR datastructures: {:?}", c)
+ }
+}
+
+/// This trait is implemented for every folding traversal. There is a fold
+/// method defined for every type of interest. Each such method has a default
+/// that does an "identity" fold.
+///
+/// A blanket implementation of this trait (that defers to the relevant
+/// method of [`TypeFolder`]) is provided for all infallible folders in
+/// order to ensure the two APIs are coherent.
+pub trait FallibleTypeFolder<'tcx>: Sized {
+ type Error;
+
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ r.try_super_fold_with(self)
+ }
+
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+ c.try_super_fold_with(self)
+ }
+
+ fn try_fold_unevaluated(
+ &mut self,
+ c: ty::Unevaluated<'tcx>,
+ ) -> Result<ty::Unevaluated<'tcx>, Self::Error> {
+ c.try_super_fold_with(self)
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ p.try_super_fold_with(self)
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ bug!("most type folders should not be folding MIR datastructures: {:?}", c)
+ }
+}
+
+// This blanket implementation of the fallible trait for infallible folders
+// delegates to infallible methods to ensure coherence.
+impl<'tcx, F> FallibleTypeFolder<'tcx> for F
+where
+ F: TypeFolder<'tcx>,
+{
+ type Error = !;
+
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ TypeFolder::tcx(self)
+ }
+
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ Ok(self.fold_binder(t))
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
+ Ok(self.fold_ty(t))
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
+ Ok(self.fold_region(r))
+ }
+
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
+ Ok(self.fold_const(c))
+ }
+
+ fn try_fold_unevaluated(
+ &mut self,
+ c: ty::Unevaluated<'tcx>,
+ ) -> Result<ty::Unevaluated<'tcx>, !> {
+ Ok(self.fold_unevaluated(c))
+ }
+
+ fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
+ Ok(self.fold_predicate(p))
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, !> {
+ Ok(self.fold_mir_const(c))
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// 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(ty::Const<'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(ty::Const<'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: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ let ct = ct.super_fold_with(self);
+ (self.ct_op)(ct)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Region folder
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// 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,
+ mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
+ ) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ value.fold_with(&mut RegionFolder::new(self, &mut f))
+ }
+}
+
+/// 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>,
+
+ /// 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>,
+ fold_region_fn: &'a mut dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
+ ) -> RegionFolder<'a, 'tcx> {
+ RegionFolder { tcx, 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<'tcx, T>,
+ ) -> ty::Binder<'tcx, T> {
+ self.current_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.current_index.shift_out(1);
+ t
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
+ ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
+ debug!(?self.current_index, "skipped bound region");
+ r
+ }
+ _ => {
+ debug!(?self.current_index, "folding free region");
+ (self.fold_region_fn)(r, self.current_index)
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Bound vars replacer
+
+pub trait BoundVarReplacerDelegate<'tcx> {
+ fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>;
+ fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>;
+ fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>;
+}
+
+pub struct FnMutDelegate<R, T, C> {
+ pub regions: R,
+ pub types: T,
+ pub consts: C,
+}
+impl<'tcx, R, T, C> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<R, T, C>
+where
+ R: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ T: FnMut(ty::BoundTy) -> Ty<'tcx>,
+ C: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
+{
+ fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
+ (self.regions)(br)
+ }
+ fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
+ (self.types)(bt)
+ }
+ fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+ (self.consts)(bv, ty)
+ }
+}
+
+/// Replaces the escaping bound vars (late bound regions or bound types) in a type.
+struct BoundVarReplacer<'tcx, D> {
+ tcx: TyCtxt<'tcx>,
+
+ /// As with `RegionFolder`, represents the index of a binder *just outside*
+ /// the ones we have visited.
+ current_index: ty::DebruijnIndex,
+
+ delegate: D,
+}
+
+impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> {
+ fn new(tcx: TyCtxt<'tcx>, delegate: D) -> Self {
+ BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate }
+ }
+}
+
+impl<'tcx, D> TypeFolder<'tcx> for BoundVarReplacer<'tcx, D>
+where
+ D: BoundVarReplacerDelegate<'tcx>,
+{
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> ty::Binder<'tcx, 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 ty = self.delegate.replace_ty(bound_ty);
+ ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
+ }
+ _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
+ _ => t,
+ }
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
+ ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
+ let region = self.delegate.replace_region(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.reuse_or_mk_region(region, ty::ReLateBound(debruijn, br))
+ } else {
+ region
+ }
+ }
+ _ => r,
+ }
+ }
+
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ match ct.kind() {
+ ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
+ let ct = self.delegate.replace_const(bound_const, ct.ty());
+ ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32())
+ }
+ _ => ct.super_fold_with(self),
+ }
+ }
+
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
+ }
+}
+
+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 `BoundRegionKind`; multiple references to the
+ /// same `BoundRegionKind` will reuse the previous result. A map is
+ /// returned at the end with each bound region and the free region
+ /// that replaced it.
+ ///
+ /// # Panics
+ ///
+ /// This method only replaces late bound regions. Any types or
+ /// constants bound by `value` will cause an ICE.
+ pub fn replace_late_bound_regions<T, F>(
+ self,
+ value: Binder<'tcx, T>,
+ mut fld_r: F,
+ ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+ where
+ F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ T: TypeFoldable<'tcx>,
+ {
+ let mut region_map = BTreeMap::new();
+ let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
+ let value = self.replace_late_bound_regions_uncached(value, real_fld_r);
+ (value, region_map)
+ }
+
+ pub fn replace_late_bound_regions_uncached<T, F>(
+ self,
+ value: Binder<'tcx, T>,
+ replace_regions: F,
+ ) -> T
+ where
+ F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ T: TypeFoldable<'tcx>,
+ {
+ let value = value.skip_binder();
+ if !value.has_escaping_bound_vars() {
+ value
+ } else {
+ let delegate = FnMutDelegate {
+ regions: replace_regions,
+ types: |b| bug!("unexpected bound ty in binder: {b:?}"),
+ consts: |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
+ };
+ let mut replacer = BoundVarReplacer::new(self, delegate);
+ value.fold_with(&mut replacer)
+ }
+ }
+
+ /// 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_uncached<T: TypeFoldable<'tcx>>(
+ self,
+ value: T,
+ delegate: impl BoundVarReplacerDelegate<'tcx>,
+ ) -> T {
+ if !value.has_escaping_bound_vars() {
+ value
+ } else {
+ let mut replacer = BoundVarReplacer::new(self, delegate);
+ value.fold_with(&mut replacer)
+ }
+ }
+
+ /// Replaces all types or regions bound by the given `Binder`. The `fld_r`
+ /// closure replaces bound regions, the `fld_t` closure replaces bound
+ /// types, and `fld_c` replaces bound constants.
+ pub fn replace_bound_vars_uncached<T: TypeFoldable<'tcx>>(
+ self,
+ value: Binder<'tcx, T>,
+ delegate: impl BoundVarReplacerDelegate<'tcx>,
+ ) -> T {
+ self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate)
+ }
+
+ /// 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<'tcx, T>,
+ ) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ self.replace_late_bound_regions_uncached(value, |br| {
+ self.mk_region(ty::ReFree(ty::FreeRegion {
+ scope: all_outlive_scope,
+ bound_region: br.kind,
+ }))
+ })
+ }
+
+ pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ let shift_bv = |bv: ty::BoundVar| ty::BoundVar::from_usize(bv.as_usize() + bound_vars);
+ self.replace_escaping_bound_vars_uncached(
+ value,
+ FnMutDelegate {
+ regions: |r: ty::BoundRegion| {
+ self.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: shift_bv(r.var), kind: r.kind },
+ ))
+ },
+ types: |t: ty::BoundTy| {
+ self.mk_ty(ty::Bound(
+ ty::INNERMOST,
+ ty::BoundTy { var: shift_bv(t.var), kind: t.kind },
+ ))
+ },
+ consts: |c, ty: Ty<'tcx>| {
+ self.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)),
+ ty,
+ })
+ },
+ },
+ )
+ }
+
+ /// 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<'tcx, 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 0 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<'tcx, T>) -> Binder<'tcx, T>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ let mut counter = 0;
+ let inner = self
+ .replace_late_bound_regions(sig, |_| {
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_u32(counter),
+ kind: ty::BrAnon(counter),
+ };
+ let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
+ counter += 1;
+ r
+ })
+ .0;
+ let bound_vars = self.mk_bound_variable_kinds(
+ (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
+ );
+ Binder::bind_with_vars(inner, bound_vars)
+ }
+
+ /// Anonymize all bound variables in `value`, this is mostly used to improve caching.
+ pub fn anonymize_bound_vars<T>(self, value: Binder<'tcx, T>) -> Binder<'tcx, T>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ struct Anonymize<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ map: &'a mut FxIndexMap<ty::BoundVar, ty::BoundVariableKind>,
+ }
+ impl<'tcx> BoundVarReplacerDelegate<'tcx> for Anonymize<'_, 'tcx> {
+ fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
+ let entry = self.map.entry(br.var);
+ let index = entry.index();
+ let var = ty::BoundVar::from_usize(index);
+ let kind = entry
+ .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(index as u32)))
+ .expect_region();
+ let br = ty::BoundRegion { var, kind };
+ self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
+ }
+ fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
+ let entry = self.map.entry(bt.var);
+ let index = entry.index();
+ let var = ty::BoundVar::from_usize(index);
+ let kind = entry
+ .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon))
+ .expect_ty();
+ self.tcx.mk_ty(ty::Bound(ty::INNERMOST, BoundTy { var, kind }))
+ }
+ fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+ let entry = self.map.entry(bv);
+ let index = entry.index();
+ let var = ty::BoundVar::from_usize(index);
+ let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
+ self.tcx.mk_const(ty::ConstS { ty, kind: ty::ConstKind::Bound(ty::INNERMOST, var) })
+ }
+ }
+
+ let mut map = Default::default();
+ let delegate = Anonymize { tcx: self, map: &mut map };
+ let inner = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate);
+ let bound_vars = self.mk_bound_variable_kinds(map.into_values());
+ Binder::bind_with_vars(inner, bound_vars)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// 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.
+
+struct Shifter<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ current_index: ty::DebruijnIndex,
+ amount: u32,
+}
+
+impl<'tcx> Shifter<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
+ Shifter { tcx, current_index: ty::INNERMOST, amount }
+ }
+}
+
+impl<'tcx> 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<'tcx, T>,
+ ) -> ty::Binder<'tcx, 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 = debruijn.shifted_in(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 = debruijn.shifted_in(self.amount);
+ self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
+ }
+ }
+
+ _ => ty.super_fold_with(self),
+ }
+ }
+
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.kind() {
+ if self.amount == 0 || debruijn < self.current_index {
+ ct
+ } else {
+ let debruijn = debruijn.shifted_in(self.amount);
+ self.tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Bound(debruijn, bound_ct),
+ ty: 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))
+}
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
new file mode 100644
index 000000000..add2df258
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -0,0 +1,349 @@
+use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
+use crate::ty;
+use crate::ty::subst::{Subst, SubstsRef};
+use crate::ty::EarlyBinder;
+use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
+
+use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub enum GenericParamDefKind {
+ Lifetime,
+ Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
+ Const { has_default: bool },
+}
+
+impl GenericParamDefKind {
+ pub fn descr(&self) -> &'static str {
+ match self {
+ GenericParamDefKind::Lifetime => "lifetime",
+ GenericParamDefKind::Type { .. } => "type",
+ GenericParamDefKind::Const { .. } => "constant",
+ }
+ }
+ pub fn to_ord(&self) -> ast::ParamKindOrd {
+ match self {
+ GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
+ GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
+ GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
+ }
+ }
+
+ pub fn is_ty_or_const(&self) -> bool {
+ match self {
+ GenericParamDefKind::Lifetime => false,
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
+ }
+ }
+
+ pub fn is_synthetic(&self) -> bool {
+ match self {
+ GenericParamDefKind::Type { synthetic, .. } => *synthetic,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, 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 has_default(&self) -> bool {
+ match self.kind {
+ GenericParamDefKind::Type { has_default, .. }
+ | GenericParamDefKind::Const { has_default } => has_default,
+ GenericParamDefKind::Lifetime => false,
+ }
+ }
+
+ pub fn default_value<'tcx>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
+ match self.kind {
+ GenericParamDefKind::Type { has_default, .. } if has_default => {
+ Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into()))
+ }
+ GenericParamDefKind::Const { has_default } if has_default => {
+ Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into()))
+ }
+ _ => None,
+ }
+ }
+}
+
+#[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, TyEncodable, TyDecodable, 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 {
+ #[inline]
+ 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();
+
+ 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 own_defaults(&self) -> GenericParamCount {
+ let mut own_defaults = GenericParamCount::default();
+
+ for param in &self.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime => (),
+ GenericParamDefKind::Type { has_default, .. } => {
+ own_defaults.types += has_default as usize;
+ }
+ GenericParamDefKind::Const { has_default } => {
+ own_defaults.consts += has_default as usize;
+ }
+ }
+ }
+
+ own_defaults
+ }
+
+ 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
+ }
+
+ /// Returns the `GenericParamDef` with the given index.
+ pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
+ if let Some(index) = param_index.checked_sub(self.parent_count) {
+ &self.params[index]
+ } else {
+ tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
+ .param_at(param_index, tcx)
+ }
+ }
+
+ /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`.
+ pub fn region_param(
+ &'tcx self,
+ param: &EarlyBoundRegion,
+ tcx: TyCtxt<'tcx>,
+ ) -> &'tcx GenericParamDef {
+ let param = self.param_at(param.index as usize, tcx);
+ match param.kind {
+ GenericParamDefKind::Lifetime => param,
+ _ => bug!("expected lifetime parameter, but found another generic parameter"),
+ }
+ }
+
+ /// Returns the `GenericParamDef` associated with this `ParamTy`.
+ pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
+ let param = self.param_at(param.index as usize, tcx);
+ match param.kind {
+ GenericParamDefKind::Type { .. } => param,
+ _ => bug!("expected type parameter, but found another generic parameter"),
+ }
+ }
+
+ /// Returns the `GenericParamDef` associated with this `ParamConst`.
+ pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
+ let param = self.param_at(param.index as usize, tcx);
+ match param.kind {
+ GenericParamDefKind::Const { .. } => param,
+ _ => bug!("expected const parameter, but found another generic parameter"),
+ }
+ }
+
+ /// Returns `true` if `params` has `impl Trait`.
+ pub fn has_impl_trait(&'tcx self) -> bool {
+ self.params.iter().any(|param| {
+ matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
+ })
+ }
+
+ /// Returns the substs corresponding to the generic parameters
+ /// of this item, excluding `Self`.
+ ///
+ /// **This should only be used for diagnostics purposes.**
+ pub fn own_substs_no_defaults(
+ &'tcx self,
+ tcx: TyCtxt<'tcx>,
+ substs: &'tcx [ty::GenericArg<'tcx>],
+ ) -> &'tcx [ty::GenericArg<'tcx>] {
+ let mut own_params = self.parent_count..self.count();
+ if self.has_self && self.parent.is_none() {
+ own_params.start = 1;
+ }
+
+ // Filter the default arguments.
+ //
+ // This currently uses structural equality instead
+ // of semantic equivalance. While not ideal, that's
+ // good enough for now as this should only be used
+ // for diagnostics anyways.
+ own_params.end -= self
+ .params
+ .iter()
+ .rev()
+ .take_while(|param| {
+ param.default_value(tcx).map_or(false, |default| {
+ default.subst(tcx, substs) == substs[param.index as usize]
+ })
+ })
+ .count();
+
+ &substs[own_params]
+ }
+
+ /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`.
+ ///
+ /// **This should only be used for diagnostics purposes.**
+ pub fn own_substs(
+ &'tcx self,
+ substs: &'tcx [ty::GenericArg<'tcx>],
+ ) -> &'tcx [ty::GenericArg<'tcx>] {
+ let own = &substs[self.parent_count..][..self.params.len()];
+ if self.has_self && self.parent.is_none() { &own[1..] } else { &own }
+ }
+}
+
+/// Bounds on generics.
+#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, 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, _)| EarlyBinder(*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, _)| EarlyBinder(*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));
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
new file mode 100644
index 000000000..cd00b26b8
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -0,0 +1,135 @@
+//! This module contains `HashStable` implementations for various data types
+//! from `rustc_middle::ty` in no particular order.
+
+use crate::middle::region;
+use crate::mir;
+use crate::ty;
+use crate::ty::fast_reject::SimplifiedType;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_query_system::ich::StableHashingContext;
+use std::cell::RefCell;
+
+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, HashingControls), Fingerprint>> =
+ RefCell::new(Default::default());
+ }
+
+ let hash = CACHE.with(|cache| {
+ let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls());
+ 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> ToStableHashKey<StableHashingContext<'a>> for SimplifiedType {
+ 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, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArgKind<'tcx> {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ match self {
+ // WARNING: We dedup cache the `HashStable` results for `List`
+ // while ignoring types and freely transmute
+ // between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`.
+ // See `fn intern_type_list` for more details.
+ //
+ // We therefore hash types without adding a hash for their discriminant.
+ //
+ // In order to make it very unlikely for the sequence of bytes being hashed for
+ // a `GenericArgKind::Type` to be the same as the sequence of bytes being
+ // hashed for one of the other variants, we hash some very high number instead
+ // of their actual discriminant since `TyKind` should never start with anything
+ // that high.
+ ty::subst::GenericArgKind::Type(ty) => ty.hash_stable(hcx, hasher),
+ ty::subst::GenericArgKind::Const(ct) => {
+ 0xF3u8.hash_stable(hcx, hasher);
+ ct.hash_stable(hcx, hasher);
+ }
+ ty::subst::GenericArgKind::Lifetime(lt) => {
+ 0xF5u8.hash_stable(hcx, hasher);
+ lt.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");
+ tcx.try_get_global_alloc(*self).hash_stable(hcx, hasher);
+ });
+ }
+}
+
+// `Relocations` with default type parameters is a sorted map.
+impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Prov>
+where
+ Prov: 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
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
new file mode 100644
index 000000000..c4ad698ba
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
@@ -0,0 +1,145 @@
+use crate::ty::context::TyCtxt;
+use crate::ty::{DefId, DefIdTree};
+use rustc_span::def_id::CRATE_DEF_ID;
+use smallvec::SmallVec;
+use std::mem;
+
+use DefIdForest::*;
+
+/// 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.
+///
+/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
+/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
+/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
+#[derive(Copy, Clone, HashStable, Debug)]
+pub enum DefIdForest<'a> {
+ Empty,
+ Single(DefId),
+ /// This variant is very rare.
+ /// Invariant: >1 elements
+ Multiple(&'a [DefId]),
+}
+
+/// Tests whether a slice of roots contains a given DefId.
+#[inline]
+fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
+ slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
+}
+
+impl<'tcx> DefIdForest<'tcx> {
+ /// Creates an empty forest.
+ pub fn empty() -> DefIdForest<'tcx> {
+ DefIdForest::Empty
+ }
+
+ /// Creates a forest consisting of a single tree representing the entire
+ /// crate.
+ #[inline]
+ pub fn full() -> DefIdForest<'tcx> {
+ DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
+ }
+
+ /// Creates a forest containing a `DefId` and all its descendants.
+ pub fn from_id(id: DefId) -> DefIdForest<'tcx> {
+ DefIdForest::Single(id)
+ }
+
+ fn as_slice(&self) -> &[DefId] {
+ match self {
+ Empty => &[],
+ Single(id) => std::slice::from_ref(id),
+ Multiple(root_ids) => root_ids,
+ }
+ }
+
+ // Only allocates in the rare `Multiple` case.
+ fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> {
+ match &root_ids[..] {
+ [] => Empty,
+ [id] => Single(*id),
+ _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)),
+ }
+ }
+
+ /// Tests whether the forest is empty.
+ pub fn is_empty(&self) -> bool {
+ match self {
+ Empty => true,
+ Single(..) | Multiple(..) => false,
+ }
+ }
+
+ /// Iterate over the set of roots.
+ fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
+ self.as_slice().iter().copied()
+ }
+
+ /// Tests whether the forest contains a given DefId.
+ pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
+ slice_contains(tcx, self.as_slice(), id)
+ }
+
+ /// Calculate the intersection of a collection of forests.
+ pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
+ where
+ I: IntoIterator<Item = DefIdForest<'tcx>>,
+ {
+ let mut iter = iter.into_iter();
+ let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
+ SmallVec::from_slice(first.as_slice())
+ } else {
+ return DefIdForest::full();
+ };
+
+ let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
+ for next_forest in iter {
+ // No need to continue if the intersection is already empty.
+ if ret.is_empty() || next_forest.is_empty() {
+ return DefIdForest::empty();
+ }
+
+ // We keep the elements in `ret` that are also in `next_forest`.
+ next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
+ // We keep the elements in `next_forest` that are also in `ret`.
+ next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
+
+ mem::swap(&mut next_ret, &mut ret);
+ next_ret.clear();
+ }
+ DefIdForest::from_vec(tcx, ret)
+ }
+
+ /// Calculate the union of a collection of forests.
+ pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
+ where
+ I: IntoIterator<Item = DefIdForest<'tcx>>,
+ {
+ let mut ret: SmallVec<[_; 1]> = SmallVec::new();
+ let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
+ for next_forest in iter {
+ // Union with the empty set is a no-op.
+ if next_forest.is_empty() {
+ continue;
+ }
+
+ // We add everything in `ret` that is not in `next_forest`.
+ next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
+ // We add everything in `next_forest` that we haven't added yet.
+ for id in next_forest.iter() {
+ if !slice_contains(tcx, &next_ret, id) {
+ next_ret.push(id);
+ }
+ }
+
+ mem::swap(&mut next_ret, &mut ret);
+ next_ret.clear();
+ }
+ DefIdForest::from_vec(tcx, ret)
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
new file mode 100644
index 000000000..3d22f5a04
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -0,0 +1,234 @@
+pub use self::def_id_forest::DefIdForest;
+
+use crate::ty;
+use crate::ty::context::TyCtxt;
+use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
+use crate::ty::{AdtKind, Visibility};
+use crate::ty::{DefId, SubstsRef};
+
+use rustc_type_ir::sty::TyKind::*;
+
+mod def_id_forest;
+
+// The methods in this module calculate `DefIdForest`s of modules in which an
+// `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
+ /// ```
+ /// #![feature(never_type)]
+ /// # fn main() {}
+ /// enum Void {}
+ /// mod a {
+ /// pub mod b {
+ /// pub struct SecretlyUninhabited {
+ /// _priv: !,
+ /// }
+ /// }
+ /// }
+ ///
+ /// mod c {
+ /// use super::Void;
+ /// 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
+ /// ```ignore (illustrative)
+ /// 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>,
+ param_env: ty::ParamEnv<'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, param_env).contains(self, module)
+ }
+}
+
+impl<'tcx> AdtDef<'tcx> {
+ /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
+ fn uninhabited_from(
+ self,
+ tcx: TyCtxt<'tcx>,
+ substs: SubstsRef<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> DefIdForest<'tcx> {
+ // 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(), param_env)),
+ )
+ }
+ }
+}
+
+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,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> DefIdForest<'tcx> {
+ 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, param_env)),
+ )
+ }
+ }
+}
+
+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,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> DefIdForest<'tcx> {
+ let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
+ // 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> Ty<'tcx> {
+ /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
+ fn uninhabited_from(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> DefIdForest<'tcx> {
+ tcx.type_uninhabited_from(param_env.and(self))
+ }
+}
+
+// Query provider for `type_uninhabited_from`.
+pub(crate) fn type_uninhabited_from<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> DefIdForest<'tcx> {
+ let ty = key.value;
+ let param_env = key.param_env;
+ match *ty.kind() {
+ Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
+
+ Never => DefIdForest::full(),
+
+ Tuple(ref tys) => {
+ DefIdForest::union(tcx, tys.iter().map(|ty| ty.uninhabited_from(tcx, param_env)))
+ }
+
+ Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
+ Some(0) | None => DefIdForest::empty(),
+ // If the array is definitely non-empty, it's uninhabited if
+ // the type of its elements is uninhabited.
+ Some(1..) => ty.uninhabited_from(tcx, param_env),
+ },
+
+ // References to uninitialised memory are 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/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
new file mode 100644
index 000000000..53218225d
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -0,0 +1,746 @@
+use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::ty::print::{FmtPrinter, Printer};
+use crate::ty::subst::{InternalSubsts, Subst};
+use crate::ty::{
+ self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable,
+};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::Namespace;
+use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::lang_items::LangItem;
+use rustc_macros::HashStable;
+use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
+use rustc_span::Symbol;
+
+use std::fmt;
+
+/// A monomorphized `InstanceDef`.
+///
+/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
+/// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval
+/// will do all required substitution as they run.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, Lift)]
+pub struct Instance<'tcx> {
+ pub def: InstanceDef<'tcx>,
+ pub substs: SubstsRef<'tcx>,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub enum InstanceDef<'tcx> {
+ /// A user-defined callable item.
+ ///
+ /// This includes:
+ /// - `fn` items
+ /// - closures
+ /// - generators
+ Item(ty::WithOptConstParam<DefId>),
+
+ /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
+ ///
+ /// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR.
+ /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
+ /// caller.
+ Intrinsic(DefId),
+
+ /// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the
+ /// `unsized_locals` feature).
+ ///
+ /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
+ /// and dereference the argument to call the original function.
+ 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_*` (generated `FnTrait` implementation for `fn()` pointers).
+ ///
+ /// `DefId` is `FnTrait::call_*`.
+ FnPtrShim(DefId, Ty<'tcx>),
+
+ /// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
+ ///
+ /// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be
+ /// codegen'd as virtual calls through the vtable.
+ ///
+ /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more
+ /// details on that).
+ Virtual(DefId, usize),
+
+ /// `<[FnMut closure] as FnOnce>::call_once`.
+ ///
+ /// The `DefId` is the ID of the `call_once` method in `FnOnce`.
+ ClosureOnceShim { call_once: DefId, track_caller: bool },
+
+ /// `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>>),
+
+ /// Compiler-generated `<T as Clone>::clone` implementation.
+ ///
+ /// For all types that automatically implement `Copy`, a trivial `Clone` impl is provided too.
+ /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`.
+ ///
+ /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
+ CloneShim(DefId, Ty<'tcx>),
+}
+
+impl<'tcx> Instance<'tcx> {
+ /// Returns the `Ty` corresponding to this `Instance`, with generic substitutions applied and
+ /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
+ pub fn ty(&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.
+ self.substs.non_erasable_generics().next()?;
+
+ match self.def {
+ InstanceDef::Item(def) => tcx
+ .upstream_monomorphizations_for(def.did)
+ .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) => def.did,
+ 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, track_caller: _ }
+ | InstanceDef::DropGlue(def_id, _)
+ | InstanceDef::CloneShim(def_id, _) => def_id,
+ }
+ }
+
+ /// Returns the `DefId` of instances which might not require codegen locally.
+ pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
+ match self {
+ ty::InstanceDef::Item(def) => Some(def.did),
+ ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
+ InstanceDef::VTableShim(..)
+ | InstanceDef::ReifyShim(..)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::Virtual(..)
+ | InstanceDef::Intrinsic(..)
+ | InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::CloneShim(..) => None,
+ }
+ }
+
+ #[inline]
+ pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
+ match self {
+ InstanceDef::Item(def) => def,
+ 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, track_caller: _ }
+ | InstanceDef::DropGlue(def_id, _)
+ | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
+ }
+ }
+
+ #[inline]
+ pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> {
+ tcx.get_attrs(self.def_id(), attr)
+ }
+
+ /// 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 rustc_hir::definitions::DefPathData;
+ let def_id = match *self {
+ ty::InstanceDef::Item(def) => def.did,
+ ty::InstanceDef::DropGlue(_, Some(_)) => return false,
+ _ => return true,
+ };
+ matches!(
+ tcx.def_key(def_id).disambiguated_data.data,
+ DefPathData::Ctor | DefPathData::ClosureExpr
+ )
+ }
+
+ /// 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_else(
+ || 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(ty::WithOptConstParam { did: def_id, .. })
+ | InstanceDef::Virtual(def_id, _) => {
+ tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+ }
+ InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller,
+ _ => false,
+ }
+ }
+
+ /// Returns `true` when the MIR body associated with this instance should be monomorphized
+ /// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see
+ /// `Instance::substs_for_mir_body`).
+ ///
+ /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR
+ /// body should perform necessary substitutions.
+ pub fn has_polymorphic_mir_body(&self) -> bool {
+ match *self {
+ InstanceDef::CloneShim(..)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::DropGlue(_, Some(_)) => false,
+ InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::Item(_)
+ | InstanceDef::Intrinsic(..)
+ | InstanceDef::ReifyShim(..)
+ | InstanceDef::Virtual(..)
+ | InstanceDef::VTableShim(..) => true,
+ }
+ }
+}
+
+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");
+ let s = FmtPrinter::new(tcx, Namespace::ValueNS)
+ .print_def_path(self.def_id(), substs)?
+ .into_buffer();
+ f.write_str(&s)
+ })?;
+
+ 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(_, None) => write!(f, " - shim(None)"),
+ InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", 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(ty::WithOptConstParam::unknown(def_id)), substs }
+ }
+
+ pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
+ let substs = InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+ ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+ ty::GenericParamDefKind::Type { .. } => {
+ bug!("Instance::mono: {:?} has type parameters", def_id)
+ }
+ ty::GenericParamDefKind::Const { .. } => {
+ bug!("Instance::mono: {:?} has const parameters", def_id)
+ }
+ });
+
+ Instance::new(def_id, substs)
+ }
+
+ #[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 `Ok(None)` if we cannot resolve `Instance` to a specific instance.
+ /// For example, in a context like this,
+ ///
+ /// ```ignore (illustrative)
+ /// fn foo<T: Debug>(t: T) { ... }
+ /// ```
+ ///
+ /// trying to resolve `Debug::fmt` applied to `T` will yield `Ok(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
+ /// `Ok(Some(instance))`.
+ ///
+ /// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process
+ /// couldn't complete due to errors elsewhere - this is distinct
+ /// from `Ok(None)` to avoid misleading diagnostics when an error
+ /// has already been/will be emitted, for the original cause
+ pub fn resolve(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
+ Instance::resolve_opt_const_arg(
+ tcx,
+ param_env,
+ ty::WithOptConstParam::unknown(def_id),
+ substs,
+ )
+ }
+
+ // This should be kept up to date with `resolve`.
+ pub fn resolve_opt_const_arg(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ def: ty::WithOptConstParam<DefId>,
+ substs: SubstsRef<'tcx>,
+ ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
+ // All regions in the result of this query are erased, so it's
+ // fine to erase all of the input regions.
+
+ // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)`
+ // below is more likely to ignore the bounds in scope (e.g. if the only
+ // generic parameters mentioned by `substs` were lifetime ones).
+ let substs = tcx.erase_regions(substs);
+
+ // FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
+ if let Some((did, param_did)) = def.as_const_arg() {
+ tcx.resolve_instance_of_const_arg(
+ tcx.erase_regions(param_env.and((did, param_did, substs))),
+ )
+ } else {
+ tcx.resolve_instance(tcx.erase_regions(param_env.and((def.did, 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);
+ // Use either `resolve_closure` or `resolve_for_vtable`
+ assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {:?}", def_id);
+ Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
+ match resolved.def {
+ InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
+ debug!(" => fn pointer created for function with #[track_caller]");
+ resolved.def = InstanceDef::ReifyShim(def.did);
+ }
+ 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_for_vtable(def_id={:?}, substs={:?})", def_id, substs);
+ let fn_sig = tcx.fn_sig(def_id);
+ let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
+ && 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).ok().flatten().map(|mut resolved| {
+ match resolved.def {
+ InstanceDef::Item(def) => {
+ // We need to generate a shim when we cannot guarantee that
+ // the caller of a trait object method will be aware of
+ // `#[track_caller]` - this ensures that the caller
+ // and callee ABI will always match.
+ //
+ // The shim is generated when all of these conditions are met:
+ //
+ // 1) The underlying method expects a caller location parameter
+ // in the ABI
+ if resolved.def.requires_caller_location(tcx)
+ // 2) The caller location parameter comes from having `#[track_caller]`
+ // on the implementation, and *not* on the trait method.
+ && !tcx.should_inherit_track_caller(def.did)
+ // If the method implementation comes from the trait definition itself
+ // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
+ // then we don't need to generate a shim. This check is needed because
+ // `should_inherit_track_caller` returns `false` if our method
+ // implementation comes from the trait block, and not an impl block
+ && !matches!(
+ tcx.opt_associated_item(def.did),
+ Some(ty::AssocItem {
+ container: ty::AssocItemContainer::TraitContainer,
+ ..
+ })
+ )
+ {
+ if tcx.is_closure(def.did) {
+ debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
+ def.did, def_id, substs);
+
+ // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
+ // - unlike functions, invoking a closure always goes through a
+ // trait.
+ resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs };
+ } else {
+ debug!(
+ " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did
+ );
+ resolved.def = InstanceDef::ReifyShim(def.did);
+ }
+ }
+ }
+ InstanceDef::Virtual(def_id, _) => {
+ debug!(" => vtable fn pointer created for virtual call");
+ resolved.def = InstanceDef::ReifyShim(def_id);
+ }
+ _ => {}
+ }
+
+ resolved
+ })
+ }
+ }
+
+ pub fn resolve_closure(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ substs: ty::SubstsRef<'tcx>,
+ requested_kind: ty::ClosureKind,
+ ) -> Option<Instance<'tcx>> {
+ let actual_kind = substs.as_closure().kind();
+
+ match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
+ Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs),
+ _ => Some(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(LangItem::DropInPlace, None);
+ let substs = tcx.intern_substs(&[ty.into()]);
+ Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap()
+ }
+
+ pub fn fn_once_adapter_instance(
+ tcx: TyCtxt<'tcx>,
+ closure_did: DefId,
+ substs: ty::SubstsRef<'tcx>,
+ ) -> Option<Instance<'tcx>> {
+ debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs);
+ let fn_once = tcx.require_lang_item(LangItem::FnOnce, None);
+ let call_once = tcx
+ .associated_items(fn_once)
+ .in_definition_order()
+ .find(|it| it.kind == ty::AssocKind::Fn)
+ .unwrap()
+ .def_id;
+ let track_caller =
+ tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER);
+ let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller };
+
+ let self_ty = tcx.mk_closure(closure_did, substs);
+
+ let sig = substs.as_closure().sig();
+ let sig =
+ tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?;
+ 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);
+ Some(Instance { def, substs })
+ }
+
+ /// Depending on the kind of `InstanceDef`, the MIR body associated with an
+ /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other
+ /// cases the MIR body is expressed in terms of the types found in the substitution array.
+ /// In the former case, we want to substitute those generic types and replace them with the
+ /// values from the substs when monomorphizing the function body. But in the latter case, we
+ /// don't want to do that substitution, since it has already been done effectively.
+ ///
+ /// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if
+ /// this function returns `None`, then the MIR body does not require substitution during
+ /// codegen.
+ fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
+ if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None }
+ }
+
+ pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: &T) -> T
+ where
+ T: TypeFoldable<'tcx> + Copy,
+ {
+ if let Some(substs) = self.substs_for_mir_body() {
+ EarlyBinder(*v).subst(tcx, substs)
+ } else {
+ *v
+ }
+ }
+
+ #[inline(always)]
+ pub fn subst_mir_and_normalize_erasing_regions<T>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ v: T,
+ ) -> T
+ where
+ T: TypeFoldable<'tcx> + Clone,
+ {
+ if let Some(substs) = self.substs_for_mir_body() {
+ tcx.subst_and_normalize_erasing_regions(substs, param_env, v)
+ } else {
+ tcx.normalize_erasing_regions(param_env, v)
+ }
+ }
+
+ #[inline(always)]
+ pub fn try_subst_mir_and_normalize_erasing_regions<T>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ v: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx> + Clone,
+ {
+ if let Some(substs) = self.substs_for_mir_body() {
+ tcx.try_subst_and_normalize_erasing_regions(substs, param_env, v)
+ } else {
+ tcx.try_normalize_erasing_regions(param_env, v)
+ }
+ }
+
+ /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
+ /// identity parameters if they are determined to be unused in `instance.def`.
+ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
+ debug!("polymorphize: running polymorphization analysis");
+ if !tcx.sess.opts.unstable_opts.polymorphize {
+ return self;
+ }
+
+ let polymorphized_substs = polymorphize(tcx, self.def, self.substs);
+ debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
+ Self { def: self.def, substs: polymorphized_substs }
+ }
+}
+
+fn polymorphize<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: ty::InstanceDef<'tcx>,
+ substs: SubstsRef<'tcx>,
+) -> SubstsRef<'tcx> {
+ debug!("polymorphize({:?}, {:?})", instance, substs);
+ let unused = tcx.unused_generic_params(instance);
+ debug!("polymorphize: unused={:?}", unused);
+
+ // If this is a closure or generator then we need to handle the case where another closure
+ // from the function is captured as an upvar and hasn't been polymorphized. In this case,
+ // the unpolymorphized upvar closure would result in a polymorphized closure producing
+ // multiple mono items (and eventually symbol clashes).
+ let def_id = instance.def_id();
+ let upvars_ty = if tcx.is_closure(def_id) {
+ Some(substs.as_closure().tupled_upvars_ty())
+ } else if tcx.type_of(def_id).is_generator() {
+ Some(substs.as_generator().tupled_upvars_ty())
+ } else {
+ None
+ };
+ let has_upvars = upvars_ty.map_or(false, |ty| !ty.tuple_fields().is_empty());
+ debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
+
+ struct PolymorphizationFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ }
+
+ impl<'tcx> ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ debug!("fold_ty: ty={:?}", ty);
+ match *ty.kind() {
+ ty::Closure(def_id, substs) => {
+ let polymorphized_substs = polymorphize(
+ self.tcx,
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ substs,
+ );
+ if substs == polymorphized_substs {
+ ty
+ } else {
+ self.tcx.mk_closure(def_id, polymorphized_substs)
+ }
+ }
+ ty::Generator(def_id, substs, movability) => {
+ let polymorphized_substs = polymorphize(
+ self.tcx,
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ substs,
+ );
+ if substs == polymorphized_substs {
+ ty
+ } else {
+ self.tcx.mk_generator(def_id, polymorphized_substs, movability)
+ }
+ }
+ _ => ty.super_fold_with(self),
+ }
+ }
+ }
+
+ InternalSubsts::for_item(tcx, def_id, |param, _| {
+ let is_unused = unused.contains(param.index).unwrap_or(false);
+ debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
+ match param.kind {
+ // Upvar case: If parameter is a type parameter..
+ ty::GenericParamDefKind::Type { .. } if
+ // ..and has upvars..
+ has_upvars &&
+ // ..and this param has the same type as the tupled upvars..
+ upvars_ty == Some(substs[param.index as usize].expect_ty()) => {
+ // ..then double-check that polymorphization marked it used..
+ debug_assert!(!is_unused);
+ // ..and polymorphize any closures/generators captured as upvars.
+ let upvars_ty = upvars_ty.unwrap();
+ let polymorphized_upvars_ty = upvars_ty.fold_with(
+ &mut PolymorphizationFolder { tcx });
+ debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
+ ty::GenericArg::from(polymorphized_upvars_ty)
+ },
+
+ // Simple case: If parameter is a const or type parameter..
+ ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if
+ // ..and is within range and unused..
+ unused.contains(param.index).unwrap_or(false) =>
+ // ..then use the identity for this parameter.
+ tcx.mk_param_from_def(param),
+
+ // Otherwise, use the parameter as before.
+ _ => substs[param.index as usize],
+ }
+ })
+}
+
+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::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(()),
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
new file mode 100644
index 000000000..ad78d24e9
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -0,0 +1,3504 @@
+use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
+use crate::ty::normalize_erasing_regions::NormalizationError;
+use crate::ty::subst::Subst;
+use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable};
+use rustc_ast as ast;
+use rustc_attr as attr;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo};
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::call::{
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
+};
+use rustc_target::abi::*;
+use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
+
+use std::cmp;
+use std::fmt;
+use std::iter;
+use std::num::NonZeroUsize;
+use std::ops::Bound;
+
+use rand::{seq::SliceRandom, SeedableRng};
+use rand_xoshiro::Xoshiro128StarStar;
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers =
+ ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
+}
+
+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 from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
+ fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
+ fn repr_discr<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ repr: &ReprOptions,
+ min: i128,
+ max: i128,
+ ) -> (Integer, bool);
+}
+
+impl IntegerExt for Integer {
+ #[inline]
+ 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(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) => I8,
+ attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) => I16,
+ attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) => I32,
+ attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) => I64,
+ attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => I128,
+ attr::SignedInt(ast::IntTy::Isize) | attr::UnsignedInt(ast::UintTy::Usize) => {
+ dl.ptr_sized_integer()
+ }
+ }
+ }
+
+ fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer {
+ match ity {
+ ty::IntTy::I8 => I8,
+ ty::IntTy::I16 => I16,
+ ty::IntTy::I32 => I32,
+ ty::IntTy::I64 => I64,
+ ty::IntTy::I128 => I128,
+ ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
+ }
+ }
+ fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer {
+ match ity {
+ ty::UintTy::U8 => I8,
+ ty::UintTy::U16 => I16,
+ ty::UintTy::U32 => I32,
+ ty::UintTy::U64 => I64,
+ ty::UintTy::U128 => I128,
+ ty::UintTy::Usize => cx.data_layout().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));
+
+ 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());
+ }
+
+ let at_least = if repr.c() {
+ // This is usually I32, however it can be different on some platforms,
+ // notably hexagon and arm-none/thumb-none
+ tcx.data_layout().c_enum_min_size
+ } else {
+ // repr(Rust) enums try to be as small as possible
+ I8
+ };
+
+ // 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 {
+ #[inline]
+ 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.
+ #[inline]
+ fn to_int_ty<'tcx>(&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;
+
+/// The maximum supported number of lanes in a SIMD vector.
+///
+/// This value is selected based on backend support:
+/// * LLVM does not appear to have a vector width limit.
+/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
+pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
+
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
+pub enum LayoutError<'tcx> {
+ Unknown(Ty<'tcx>),
+ SizeOverflow(Ty<'tcx>),
+ NormalizationFailure(Ty<'tcx>, NormalizationError<'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, "values of the type `{}` are too big for the current architecture", ty)
+ }
+ LayoutError::NormalizationFailure(t, e) => write!(
+ f,
+ "unable to determine layout for `{}` because `{}` cannot be normalized",
+ t,
+ e.get_type_for_failure()
+ ),
+ }
+ }
+}
+
+/// Enforce some basic invariants on layouts.
+fn sanity_check_layout<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ layout: &TyAndLayout<'tcx>,
+) {
+ // Type-level uninhabitedness should always imply ABI uninhabitedness.
+ if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) {
+ assert!(layout.abi.is_uninhabited());
+ }
+
+ if layout.size.bytes() % layout.align.abi.bytes() != 0 {
+ bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
+ }
+
+ if cfg!(debug_assertions) {
+ fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
+ match layout.abi() {
+ Abi::Scalar(scalar) => {
+ // No padding in scalars.
+ assert_eq!(
+ layout.align().abi,
+ scalar.align(&tcx).abi,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ assert_eq!(
+ layout.size(),
+ scalar.size(&tcx),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ }
+ Abi::Vector { count, element } => {
+ // No padding in vectors. Alignment can be strengthened, though.
+ assert!(
+ layout.align().abi >= element.align(&tcx).abi,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ let size = element.size(&tcx) * count;
+ assert_eq!(
+ layout.size(),
+ size.align_to(tcx.data_layout().vector_align(size).abi),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ }
+ Abi::ScalarPair(scalar1, scalar2) => {
+ // Sanity-check scalar pairs. These are a bit more flexible and support
+ // padding, but we can at least ensure both fields actually fit into the layout
+ // and the alignment requirement has not been weakened.
+ let align1 = scalar1.align(&tcx).abi;
+ let align2 = scalar2.align(&tcx).abi;
+ assert!(
+ layout.align().abi >= cmp::max(align1, align2),
+ "alignment mismatch between ABI and layout in {layout:#?}",
+ );
+ let field2_offset = scalar1.size(&tcx).align_to(align2);
+ assert!(
+ layout.size() >= field2_offset + scalar2.size(&tcx),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ }
+ Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
+ }
+ }
+
+ check_layout_abi(tcx, layout.layout);
+
+ if let Variants::Multiple { variants, .. } = &layout.variants {
+ for variant in variants {
+ check_layout_abi(tcx, *variant);
+ // No nested "multiple".
+ assert!(matches!(variant.variants(), Variants::Single { .. }));
+ // Skip empty variants.
+ if variant.size() == Size::ZERO
+ || variant.fields().count() == 0
+ || variant.abi().is_uninhabited()
+ {
+ // These are never actually accessed anyway, so we can skip them. (Note that
+ // sometimes, variants with fields have size 0, and sometimes, variants without
+ // fields have non-0 size.)
+ continue;
+ }
+ // Variants should have the same or a smaller size as the full thing.
+ if variant.size() > layout.size {
+ bug!(
+ "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
+ layout.size.bytes(),
+ variant.size().bytes(),
+ )
+ }
+ // The top-level ABI and the ABI of the variants should be coherent.
+ let abi_coherent = match (layout.abi, variant.abi()) {
+ (Abi::Scalar(..), Abi::Scalar(..)) => true,
+ (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
+ (Abi::Uninhabited, _) => true,
+ (Abi::Aggregate { .. }, _) => true,
+ _ => false,
+ };
+ if !abi_coherent {
+ bug!(
+ "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
+ variant
+ );
+ }
+ }
+ }
+ }
+}
+
+#[instrument(skip(tcx, query), level = "debug")]
+fn layout_of<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
+ ty::tls::with_related_context(tcx, move |icx| {
+ let (param_env, ty) = query.into_parts();
+ debug!(?ty);
+
+ if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
+ 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 param_env = param_env.with_reveal_all_normalized(tcx);
+ let unnormalized_ty = ty;
+
+ // FIXME: We might want to have two different versions of `layout_of`:
+ // One that can be called after typecheck has completed and can use
+ // `normalize_erasing_regions` here and another one that can be called
+ // before typecheck has completed and uses `try_normalize_erasing_regions`.
+ let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+ Ok(t) => t,
+ Err(normalization_error) => {
+ return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+ }
+ };
+
+ if ty != unnormalized_ty {
+ // Ensure this layout is also cached for the normalized type.
+ return tcx.layout_of(param_env.and(ty));
+ }
+
+ let cx = LayoutCx { tcx, param_env };
+
+ let layout = cx.layout_of_uncached(ty)?;
+ let layout = TyAndLayout { ty, layout };
+
+ cx.record_layout_for_printing(layout);
+
+ sanity_check_layout(tcx, param_env, &layout);
+
+ Ok(layout)
+ })
+ })
+}
+
+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 `FieldsShape::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) -> LayoutS<'tcx> {
+ let dl = self.data_layout();
+ let b_align = b.align(dl);
+ let align = a.align(dl).max(b_align).max(dl.aggregate_align);
+ let b_offset = a.size(dl).align_to(b_align.abi);
+ let size = (b_offset + b.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)
+ .into_iter()
+ .chain(Niche::from_scalar(dl, Size::ZERO, a))
+ .max_by_key(|niche| niche.available(dl));
+
+ LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::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: &[TyAndLayout<'_>],
+ repr: &ReprOptions,
+ kind: StructKind,
+ ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
+ let dl = self.data_layout();
+ let pack = repr.pack;
+ if pack.is_some() && repr.align.is_some() {
+ self.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned");
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+
+ let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
+
+ let optimize = !repr.inhibit_struct_field_reordering_opt();
+ 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: &TyAndLayout<'_>| {
+ if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi }
+ };
+
+ // If `-Z randomize-layout` was enabled for the type definition we can shuffle
+ // the field ordering to try and catch some code making assumptions about layouts
+ // we don't guarantee
+ if repr.can_randomize_type_layout() {
+ // `ReprOptions.layout_seed` is a deterministic seed that we can use to
+ // randomize field ordering with
+ let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
+
+ // Shuffle the ordering of the fields
+ optimizing.shuffle(&mut rng);
+
+ // Otherwise we just leave things alone and actually optimize the type's fields
+ } else {
+ 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(..) => {
+ // Sort in ascending alignment so that the layout stays optimal
+ // regardless of the prefix
+ optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
+ }
+ }
+
+ // FIXME(Kixiron): We can always shuffle fields within a given alignment class
+ // regardless of the status of `-Z randomize-layout`
+ }
+ }
+
+ // 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 sized = true;
+ let mut offsets = vec![Size::ZERO; fields.len()];
+ 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 {
+ self.tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "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 let Some(mut niche) = field.largest_niche {
+ 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 { invert_mapping(&inverse_memory_index) } else { 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.
+ 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;
+ }
+ // But scalar pairs are Rust-specific and get
+ // treated as aggregates by C ABIs anyway.
+ Abi::ScalarPair(..) => {
+ abi = field.abi;
+ }
+ _ => {}
+ }
+ }
+ }
+
+ // Two non-ZST fields, and they're both scalars.
+ (Some((i, a)), Some((j, b)), None) => {
+ match (a.abi, b.abi) {
+ (Abi::Scalar(a), Abi::Scalar(b)) => {
+ // 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, b);
+ let pair_offsets = match pair.fields {
+ FieldsShape::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 fields.iter().any(|f| f.abi.is_uninhabited()) {
+ abi = Abi::Uninhabited;
+ }
+
+ Ok(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Arbitrary { offsets, memory_index },
+ abi,
+ largest_niche,
+ align,
+ size,
+ })
+ }
+
+ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
+ let tcx = self.tcx;
+ let param_env = self.param_env;
+ let dl = self.data_layout();
+ let scalar_unit = |value: Primitive| {
+ let size = value.size(dl);
+ assert!(size.bits() <= 128);
+ Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
+ };
+ let scalar =
+ |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
+
+ let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
+ Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
+ };
+ debug_assert!(!ty.has_infer_types_or_consts());
+
+ Ok(match *ty.kind() {
+ // Basic scalars.
+ ty::Bool => tcx.intern_layout(LayoutS::scalar(
+ self,
+ Scalar::Initialized {
+ value: Int(I8, false),
+ valid_range: WrappingRange { start: 0, end: 1 },
+ },
+ )),
+ ty::Char => tcx.intern_layout(LayoutS::scalar(
+ self,
+ Scalar::Initialized {
+ value: Int(I32, false),
+ valid_range: WrappingRange { start: 0, end: 0x10FFFF },
+ },
+ )),
+ ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
+ ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
+ ty::Float(fty) => scalar(match fty {
+ ty::FloatTy::F32 => F32,
+ ty::FloatTy::F64 => F64,
+ }),
+ ty::FnPtr(_) => {
+ let mut ptr = scalar_unit(Pointer);
+ ptr.valid_range_mut().start = 1;
+ tcx.intern_layout(LayoutS::scalar(self, ptr))
+ }
+
+ // The never type.
+ ty::Never => tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Primitive,
+ abi: Abi::Uninhabited,
+ largest_niche: None,
+ align: dl.i8_align,
+ size: Size::ZERO,
+ }),
+
+ // Potentially-wide 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_mut().start = 1;
+ }
+
+ let pointee = tcx.normalize_erasing_regions(param_env, pointee);
+ if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
+ return Ok(tcx.intern_layout(LayoutS::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(LayoutS::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_mut().start = 1;
+ 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 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
+ Abi::Uninhabited
+ } else {
+ Abi::Aggregate { sized: true }
+ };
+
+ let largest_niche = if count != 0 { element.largest_niche } else { None };
+
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Array { stride: element.size, count },
+ abi,
+ largest_niche,
+ align: element.align,
+ size,
+ })
+ }
+ ty::Slice(element) => {
+ let element = self.layout_of(element)?;
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::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(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::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(_, ref substs) => {
+ let tys = substs.as_closure().upvar_tys();
+ 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)).collect::<Result<Vec<_>, _>>()?,
+ &ReprOptions::default(),
+ kind,
+ )?
+ }
+
+ // SIMD vector types.
+ ty::Adt(def, substs) if def.repr().simd() => {
+ if !def.is_struct() {
+ // Should have yielded E0517 by now.
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ "#[repr(simd)] was applied to an ADT that is not a struct",
+ );
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ // Supported SIMD vectors are homogeneous ADTs with at least one field:
+ //
+ // * #[repr(simd)] struct S(T, T, T, T);
+ // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T }
+ // * #[repr(simd)] struct S([T; 4])
+ //
+ // where T is a primitive scalar (integer/float/pointer).
+
+ // SIMD vectors with zero fields are not supported.
+ // (should be caught by typeck)
+ if def.non_enum_variant().fields.is_empty() {
+ tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+ }
+
+ // Type of the first ADT field:
+ let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs);
+
+ // Heterogeneous SIMD vectors are not supported:
+ // (should be caught by typeck)
+ for fi in &def.non_enum_variant().fields {
+ if fi.ty(tcx, substs) != f0_ty {
+ tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty));
+ }
+ }
+
+ // The element type and number of elements of the SIMD vector
+ // are obtained from:
+ //
+ // * the element type and length of the single array field, if
+ // the first field is of array type, or
+ //
+ // * the homogenous field type and the number of fields.
+ let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() {
+ // First ADT field is an array:
+
+ // SIMD vectors with multiple array fields are not supported:
+ // (should be caught by typeck)
+ if def.non_enum_variant().fields.len() != 1 {
+ tcx.sess.fatal(&format!(
+ "monomorphising SIMD type `{}` with more than one array field",
+ ty
+ ));
+ }
+
+ // Extract the number of elements from the layout of the array field:
+ let FieldsShape::Array { count, .. } = self.layout_of(f0_ty)?.layout.fields() else {
+ return Err(LayoutError::Unknown(ty));
+ };
+
+ (*e_ty, *count, true)
+ } else {
+ // First ADT field is not an array:
+ (f0_ty, def.non_enum_variant().fields.len() as _, false)
+ };
+
+ // SIMD vectors of zero length are not supported.
+ // Additionally, lengths are capped at 2^16 as a fixed maximum backends must
+ // support.
+ //
+ // Can't be caught in typeck if the array length is generic.
+ if e_len == 0 {
+ tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+ } else if e_len > MAX_SIMD_LANES {
+ tcx.sess.fatal(&format!(
+ "monomorphising SIMD type `{}` of length greater than {}",
+ ty, MAX_SIMD_LANES,
+ ));
+ }
+
+ // Compute the ABI of the element type:
+ let e_ly = self.layout_of(e_ty)?;
+ let Abi::Scalar(e_abi) = e_ly.abi else {
+ // This error isn't caught in typeck, e.g., if
+ // the element type of the vector is generic.
+ tcx.sess.fatal(&format!(
+ "monomorphising SIMD type `{}` with a non-primitive-scalar \
+ (integer/float/pointer) element type `{}`",
+ ty, e_ty
+ ))
+ };
+
+ // Compute the size and alignment of the vector:
+ let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?;
+ let align = dl.vector_align(size);
+ let size = size.align_to(align.abi);
+
+ // Compute the placement of the vector fields:
+ let fields = if is_array {
+ FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] }
+ } else {
+ FieldsShape::Array { stride: e_ly.size, count: e_len }
+ };
+
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields,
+ abi: Abi::Vector { element: e_abi, count: e_len },
+ largest_niche: e_ly.largest_niche,
+ 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() {
+ self.tcx.sess.delay_span_bug(
+ tcx.def_span(def.did()),
+ "union cannot be packed and aligned",
+ );
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ 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() {
+ // Discard valid range information and allow undef
+ let field_abi = match field.abi {
+ Abi::Scalar(x) => Abi::Scalar(x.to_union()),
+ Abi::ScalarPair(x, y) => {
+ Abi::ScalarPair(x.to_union(), y.to_union())
+ }
+ Abi::Vector { element: x, count } => {
+ Abi::Vector { element: x.to_union(), 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(LayoutS {
+ variants: Variants::Single { index },
+ fields: FieldsShape::Union(
+ NonZeroUsize::new(variants[index].len())
+ .ok_or(LayoutError::Unknown(ty))?,
+ ),
+ 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: &[TyAndLayout<'_>]| {
+ 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 {
+ Some(present_first) => present_first,
+ // Uninhabited because it has no variants, or only absent ones.
+ None if def.is_enum() => {
+ return Ok(tcx.layout_of(param_env.and(tcx.types.never))?.layout);
+ }
+ // If it's a struct, still compute a layout so that we can still compute the
+ // field offsets.
+ None => 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;
+ let kind = if def.is_enum() || variants[v].is_empty() {
+ StructKind::AlwaysSized
+ } else {
+ let param_env = tcx.param_env(def.did());
+ let last_field = def.variant(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 };
+
+ if def.is_unsafe_cell() {
+ let hide_niches = |scalar: &mut _| match scalar {
+ Scalar::Initialized { value, valid_range } => {
+ *valid_range = WrappingRange::full(value.size(dl))
+ }
+ // Already doesn't have any niches
+ Scalar::Union { .. } => {}
+ };
+ match &mut st.abi {
+ Abi::Uninhabited => {}
+ Abi::Scalar(scalar) => hide_niches(scalar),
+ Abi::ScalarPair(a, b) => {
+ hide_niches(a);
+ hide_niches(b);
+ }
+ Abi::Vector { element, count: _ } => hide_niches(element),
+ Abi::Aggregate { sized: _ } => {}
+ }
+ st.largest_niche = None;
+ return Ok(tcx.intern_layout(st));
+ }
+
+ 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.
+ let valid_range = scalar.valid_range_mut();
+ assert!(valid_range.start <= start);
+ valid_range.start = start;
+ }
+ if let Bound::Included(end) = end {
+ // FIXME(eddyb) this might be incorrect - it doesn't
+ // account for wrap-around (end < start) ranges.
+ let valid_range = scalar.valid_range_mut();
+ assert!(valid_range.end >= end);
+ valid_range.end = end;
+ }
+
+ // Update `largest_niche` if we have introduced a larger niche.
+ let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
+ 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()));
+
+ let mut niche_filling_layout = None;
+
+ // 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;
+
+ // Find the field with the largest niche
+ let niche_candidate = variants[i]
+ .iter()
+ .enumerate()
+ .filter_map(|(j, field)| Some((j, field.largest_niche?)))
+ .max_by_key(|(_, niche)| niche.available(dl));
+
+ if let Some((field_index, niche, (niche_start, niche_scalar))) =
+ niche_candidate.and_then(|(field_index, niche)| {
+ Some((field_index, niche, niche.reserve(self, count)?))
+ })
+ {
+ 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(tcx.intern_layout(st))
+ })
+ .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+ let offset = st[i].fields().offset(field_index) + niche.offset;
+
+ // Align the total size to the largest alignment.
+ let size = st[i].size().align_to(align.abi);
+
+ let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
+ Abi::Uninhabited
+ } else if align == st[i].align() && size == st[i].size() {
+ // When the total alignment and size match, we can use the
+ // same ABI as the scalar variant with the reserved niche.
+ match st[i].abi() {
+ Abi::Scalar(_) => Abi::Scalar(niche_scalar),
+ Abi::ScalarPair(first, second) => {
+ // Only the niche is guaranteed to be initialised,
+ // so use union layout for the other primitive.
+ if offset.bytes() == 0 {
+ Abi::ScalarPair(niche_scalar, second.to_union())
+ } else {
+ Abi::ScalarPair(first.to_union(), niche_scalar)
+ }
+ }
+ _ => Abi::Aggregate { sized: true },
+ }
+ } else {
+ Abi::Aggregate { sized: true }
+ };
+
+ let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
+
+ niche_filling_layout = Some(LayoutS {
+ variants: Variants::Multiple {
+ tag: niche_scalar,
+ tag_encoding: TagEncoding::Niche {
+ dataful_variant: i,
+ niche_variants,
+ niche_start,
+ },
+ tag_field: 0,
+ variants: st,
+ },
+ fields: FieldsShape::Arbitrary {
+ offsets: vec![offset],
+ memory_index: vec![0],
+ },
+ abi,
+ largest_niche,
+ size,
+ align,
+ });
+ }
+ }
+ }
+
+ let (mut min, mut max) = (i128::MAX, i128::MIN);
+ 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, i128::MIN) {
+ 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 {
+ FieldsShape::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 = ity.size().unsigned_int_max();
+ let tag = Scalar::Initialized {
+ value: Int(ity, signed),
+ valid_range: WrappingRange {
+ start: (min as u128 & tag_mask),
+ end: (max as u128 & tag_mask),
+ },
+ };
+ let mut abi = Abi::Aggregate { sized: true };
+
+ if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
+ abi = Abi::Uninhabited;
+ } else if tag.size(dl) == size {
+ // Make sure we only use scalar layout when the enum is entirely its
+ // own tag (i.e. it has no padding nor any non-ZST variant fields).
+ abi = Abi::Scalar(tag);
+ } else {
+ // Try to use a ScalarPair for all tagged enums.
+ let mut common_prim = None;
+ let mut common_prim_initialized_in_all_variants = true;
+ for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
+ let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
+ bug!();
+ };
+ let mut fields =
+ iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
+ let (field, offset) = match (fields.next(), fields.next()) {
+ (None, None) => {
+ common_prim_initialized_in_all_variants = false;
+ continue;
+ }
+ (Some(pair), None) => pair,
+ _ => {
+ common_prim = None;
+ break;
+ }
+ };
+ let prim = match field.abi {
+ Abi::Scalar(scalar) => {
+ common_prim_initialized_in_all_variants &=
+ matches!(scalar, Scalar::Initialized { .. });
+ scalar.primitive()
+ }
+ _ => {
+ 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 prim_scalar = if common_prim_initialized_in_all_variants {
+ scalar_unit(prim)
+ } else {
+ // Common prim might be uninit.
+ Scalar::Union { value: prim }
+ };
+ let pair = self.scalar_pair(tag, prim_scalar);
+ let pair_offsets = match pair.fields {
+ FieldsShape::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 we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
+ // variants to ensure they are consistent. This is because a downcast is
+ // semantically a NOP, and thus should not affect layout.
+ if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
+ for variant in &mut layout_variants {
+ // We only do this for variants with fields; the others are not accessed anyway.
+ // Also do not overwrite any already existing "clever" ABIs.
+ if variant.fields.count() > 0
+ && matches!(variant.abi, Abi::Aggregate { .. })
+ {
+ variant.abi = abi;
+ // Also need to bump up the size and alignment, so that the entire value fits in here.
+ variant.size = cmp::max(variant.size, size);
+ variant.align.abi = cmp::max(variant.align.abi, align.abi);
+ }
+ }
+ }
+
+ let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
+
+ let layout_variants =
+ layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
+
+ let tagged_layout = LayoutS {
+ variants: Variants::Multiple {
+ tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: 0,
+ variants: layout_variants,
+ },
+ fields: FieldsShape::Arbitrary {
+ offsets: vec![Size::ZERO],
+ memory_index: vec![0],
+ },
+ largest_niche,
+ abi,
+ align,
+ size,
+ };
+
+ let best_layout = match (tagged_layout, niche_filling_layout) {
+ (tagged_layout, Some(niche_filling_layout)) => {
+ // Pick the smaller layout; otherwise,
+ // pick the layout with the larger niche; otherwise,
+ // pick tagged as it has simpler codegen.
+ cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
+ let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl));
+ (layout.size, cmp::Reverse(niche_size))
+ })
+ }
+ (tagged_layout, None) => tagged_layout,
+ };
+
+ tcx.intern_layout(best_layout)
+ }
+
+ // Types with no meaningful known layout.
+ ty::Projection(_) | ty::Opaque(..) => {
+ // NOTE(eddyb) `layout_of` query should've normalized these away,
+ // if that was possible, so there's no reason to try again here.
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+ bug!("Layout::compute: unexpected type `{}`", ty)
+ }
+
+ ty::Bound(..) | 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 {
+ if let Assigned(idx) = assignment {
+ 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.
+ {
+ for (idx, local) in ineligible_locals.iter().enumerate() {
+ assignments[local] = Ineligible(Some(idx as u32));
+ }
+ }
+ 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<Layout<'tcx>, LayoutError<'tcx>> {
+ use SavedLocalEligibility::*;
+ let tcx = self.tcx;
+ let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs);
+
+ let Some(info) = tcx.generator_layout(def_id) else {
+ return Err(LayoutError::Unknown(ty));
+ };
+ 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 tag_index = substs.as_generator().prefix_tys().count();
+
+ // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
+ let max_discr = (info.variant_fields.len() - 1) as u128;
+ let discr_int = Integer::fit_unsigned(max_discr);
+ let discr_int_ty = discr_int.to_ty(tcx, false);
+ let tag = Scalar::Initialized {
+ value: Primitive::Int(discr_int, false),
+ valid_range: WrappingRange { start: 0, end: max_discr },
+ };
+ let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
+ let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
+
+ 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()
+ .map(|ty| self.layout_of(ty))
+ .chain(iter::once(Ok(tag_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 {
+ FieldsShape::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 = (tag_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 =
+ FieldsShape::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 FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
+ 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 = iter::zip(offsets, 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 = FieldsShape::Arbitrary {
+ offsets: combined_offsets,
+ memory_index: combined_memory_index,
+ };
+
+ size = size.max(variant.size);
+ align = align.max(variant.align);
+ Ok(tcx.intern_layout(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(LayoutS {
+ variants: Variants::Multiple {
+ tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: tag_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_of` query to record the final
+ /// layout of each type.
+ #[inline(always)]
+ fn record_layout_for_printing(&self, layout: TyAndLayout<'tcx>) {
+ // If we are running with `-Zprint-type-sizes`, maybe record layouts
+ // for dumping later.
+ if self.tcx.sess.opts.unstable_opts.print_type_sizes {
+ self.record_layout_for_printing_outlined(layout)
+ }
+ }
+
+ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'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_or_consts() || !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<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
+ let mut min_size = Size::ZERO;
+ let field_info: Vec<_> = flds
+ .iter()
+ .enumerate()
+ .map(|(i, &name)| {
+ let field_layout = layout.field(self, i);
+ let offset = layout.fields.offset(i);
+ let field_end = offset + field_layout.size;
+ if min_size < field_end {
+ min_size = field_end;
+ }
+ FieldInfo {
+ name,
+ offset: offset.bytes(),
+ size: field_layout.size.bytes(),
+ align: field_layout.align.abi.bytes(),
+ }
+ })
+ .collect();
+
+ VariantInfo {
+ name: n,
+ kind: if layout.is_unsized() { SizeKind::Min } else { 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 } => {
+ if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive {
+ debug!(
+ "print-type-size `{:#?}` variant {}",
+ layout,
+ adt_def.variant(index).name
+ );
+ let variant_def = &adt_def.variant(index);
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
+ record(
+ adt_kind.into(),
+ adt_packed,
+ None,
+ vec![build_variant_info(Some(variant_def.name), &fields, layout)],
+ );
+ } else {
+ // (This case arises for *empty* enums; so give it
+ // zero variants.)
+ record(adt_kind.into(), adt_packed, None, vec![]);
+ }
+ }
+
+ Variants::Multiple { tag, ref tag_encoding, .. } => {
+ 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.name).collect();
+ build_variant_info(
+ Some(variant_def.name),
+ &fields,
+ layout.for_variant(self, i),
+ )
+ })
+ .collect();
+ record(
+ adt_kind.into(),
+ adt_packed,
+ match tag_encoding {
+ TagEncoding::Direct => Some(tag.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_or_consts());
+
+ // 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_or_consts());
+ 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.variant(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<'tcx>) -> 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> {
+ #[inline]
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.data_layout
+ }
+}
+
+impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.sess.target
+ }
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
+ #[inline]
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ *self
+ }
+}
+
+impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
+ #[inline]
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.data_layout
+ }
+}
+
+impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.sess.target
+ }
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
+ #[inline]
+ 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: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
+ fn target_spec(&self) -> &Target {
+ self.tcx.target_spec()
+ }
+}
+
+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(Ok(x): Result<T, Self::Error>) -> Self {
+ 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 TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
+
+/// Trait for contexts that want to be able to compute layouts of types.
+/// This automatically gives access to `LayoutOf`, through a blanket `impl`.
+pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
+ /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
+ /// returned from `layout_of` (see also `handle_layout_err`).
+ type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>;
+
+ /// `Span` to use for `tcx.at(span)`, from `layout_of`.
+ // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
+ #[inline]
+ fn layout_tcx_at_span(&self) -> Span {
+ DUMMY_SP
+ }
+
+ /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
+ /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
+ ///
+ /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
+ /// but this hook allows e.g. codegen to return only `TyAndLayout` from its
+ /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
+ /// (and any `LayoutError`s are turned into fatal errors or ICEs).
+ fn handle_layout_err(
+ &self,
+ err: LayoutError<'tcx>,
+ span: Span,
+ ty: Ty<'tcx>,
+ ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
+}
+
+/// Blanket extension trait for contexts that can compute layouts of types.
+pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode, and will normalize the input type.
+ #[inline]
+ fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
+ self.spanned_layout_of(ty, DUMMY_SP)
+ }
+
+ /// Computes the layout of a type, at `span`. Note that this implicitly
+ /// executes in "reveal all" mode, and will normalize the input type.
+ // FIXME(eddyb) avoid passing information like this, and instead add more
+ // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
+ #[inline]
+ fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
+ let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
+ let tcx = self.tcx().at(span);
+
+ MaybeResult::from(
+ tcx.layout_of(self.param_env().and(ty))
+ .map_err(|err| self.handle_layout_err(err, span, ty)),
+ )
+ }
+}
+
+impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
+ type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+
+ #[inline]
+ fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
+ err
+ }
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
+ type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+
+ #[inline]
+ fn layout_tcx_at_span(&self) -> Span {
+ self.tcx.span
+ }
+
+ #[inline]
+ fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
+ err
+ }
+}
+
+impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
+where
+ C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
+{
+ fn ty_and_layout_for_variant(
+ this: TyAndLayout<'tcx>,
+ cx: &C,
+ variant_index: VariantIdx,
+ ) -> TyAndLayout<'tcx> {
+ let layout = match this.variants {
+ Variants::Single { index }
+ // If all variants but one are uninhabited, the variant layout is the enum layout.
+ if index == variant_index &&
+ // Don't confuse variants of uninhabited enums with the enum itself.
+ // For more details see https://github.com/rust-lang/rust/issues/69763.
+ this.fields != FieldsShape::Primitive =>
+ {
+ this.layout
+ }
+
+ Variants::Single { index } => {
+ let tcx = cx.tcx();
+ let param_env = cx.param_env();
+
+ // Deny calling for_variant more than once for non-Single enums.
+ if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) {
+ assert_eq!(original_layout.variants, Variants::Single { index });
+ }
+
+ let fields = match this.ty.kind() {
+ ty::Adt(def, _) if def.variants().is_empty() =>
+ bug!("for_variant called on zero-variant enum"),
+ ty::Adt(def, _) => def.variant(variant_index).fields.len(),
+ _ => bug!(),
+ };
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: variant_index },
+ fields: match NonZeroUsize::new(fields) {
+ Some(fields) => FieldsShape::Union(fields),
+ None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] },
+ },
+ abi: Abi::Uninhabited,
+ largest_niche: None,
+ align: tcx.data_layout.i8_align,
+ size: Size::ZERO,
+ })
+ }
+
+ Variants::Multiple { ref variants, .. } => variants[variant_index],
+ };
+
+ assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
+
+ TyAndLayout { ty: this.ty, layout }
+ }
+
+ fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
+ enum TyMaybeWithLayout<'tcx> {
+ Ty(Ty<'tcx>),
+ TyAndLayout(TyAndLayout<'tcx>),
+ }
+
+ fn field_ty_or_layout<'tcx>(
+ this: TyAndLayout<'tcx>,
+ cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
+ i: usize,
+ ) -> TyMaybeWithLayout<'tcx> {
+ let tcx = cx.tcx();
+ let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
+ TyAndLayout {
+ layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
+ ty: tag.primitive().to_ty(tcx),
+ }
+ };
+
+ 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!("TyAndLayout::field({:?}): 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 `FieldsShape` is checked by users.
+ if i == 0 {
+ let nil = tcx.mk_unit();
+ let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
+ tcx.mk_mut_ptr(nil)
+ } else {
+ tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
+ };
+
+ // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
+ // the `Result` should always work because the type is
+ // always either `*mut ()` or `&'static mut ()`.
+ return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
+ ty: this.ty,
+ ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+ });
+ }
+
+ match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
+ ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
+ ty::Dynamic(_, _) => {
+ TyMaybeWithLayout::Ty(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!("TyAndLayout::field({:?}): not applicable", this),
+ }
+ }
+
+ // Arrays and slices.
+ ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
+ ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
+
+ // Tuples, generators and closures.
+ ty::Closure(_, ref substs) => field_ty_or_layout(
+ TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
+ cx,
+ i,
+ ),
+
+ ty::Generator(def_id, ref substs, _) => match this.variants {
+ Variants::Single { index } => TyMaybeWithLayout::Ty(
+ substs
+ .as_generator()
+ .state_tys(def_id, tcx)
+ .nth(index.as_usize())
+ .unwrap()
+ .nth(i)
+ .unwrap(),
+ ),
+ Variants::Multiple { tag, tag_field, .. } => {
+ if i == tag_field {
+ return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
+ }
+ TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
+ }
+ },
+
+ ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
+
+ // ADTs.
+ ty::Adt(def, substs) => {
+ match this.variants {
+ Variants::Single { index } => {
+ TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
+ }
+
+ // Discriminant field for enums (where applicable).
+ Variants::Multiple { tag, .. } => {
+ assert_eq!(i, 0);
+ return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
+ }
+ }
+ }
+
+ ty::Projection(_)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Opaque(..)
+ | ty::Param(_)
+ | ty::Infer(_)
+ | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
+ }
+ }
+
+ match field_ty_or_layout(this, cx, i) {
+ TyMaybeWithLayout::Ty(field_ty) => {
+ cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
+ bug!(
+ "failed to get layout for `{}`: {},\n\
+ despite it being a field (#{}) of an existing layout: {:#?}",
+ field_ty,
+ e,
+ i,
+ this
+ )
+ })
+ }
+ TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
+ }
+ }
+
+ fn ty_and_layout_pointee_info_at(
+ this: TyAndLayout<'tcx>,
+ cx: &C,
+ offset: Size,
+ ) -> Option<PointeeInfo> {
+ let tcx = cx.tcx();
+ let param_env = cx.param_env();
+
+ let addr_space_of_ty = |ty: Ty<'tcx>| {
+ if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
+ };
+
+ let pointee_info = match *this.ty.kind() {
+ ty::RawPtr(mt) if offset.bytes() == 0 => {
+ tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
+ size: layout.size,
+ align: layout.align.abi,
+ safe: None,
+ address_space: addr_space_of_ty(mt.ty),
+ })
+ }
+ ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
+ tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
+ size: layout.size,
+ align: layout.align.abi,
+ safe: None,
+ address_space: cx.data_layout().instruction_address_space,
+ })
+ }
+ ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
+ let address_space = addr_space_of_ty(ty);
+ let kind = if tcx.sess.opts.optimize == OptLevel::No {
+ // Use conservative pointer kind if not optimizing. This saves us the
+ // Freeze/Unpin queries, and can save time in the codegen backend (noalias
+ // attributes in LLVM have compile-time cost even in unoptimized builds).
+ PointerKind::SharedMutable
+ } else {
+ match mt {
+ hir::Mutability::Not => {
+ if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
+ PointerKind::Frozen
+ } else {
+ PointerKind::SharedMutable
+ }
+ }
+ hir::Mutability::Mut => {
+ // References to self-referential structures should not be considered
+ // noalias, as another pointer to the structure can be obtained, that
+ // is not based-on the original reference. We consider all !Unpin
+ // types to be potentially self-referential here.
+ if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) {
+ PointerKind::UniqueBorrowed
+ } else {
+ PointerKind::UniqueBorrowedPinned
+ }
+ }
+ }
+ };
+
+ tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
+ size: layout.size,
+ align: layout.align.abi,
+ safe: Some(kind),
+ address_space,
+ })
+ }
+
+ _ => {
+ 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 {
+ tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+ tag_field,
+ ..
+ } if this.fields.offset(tag_field) == 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 FieldsShape::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.
+ let field_info =
+ field.pointee_info_at(cx, offset - field_start);
+ field_info
+ } 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
+ }
+ };
+
+ debug!(
+ "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
+ offset,
+ this.ty.kind(),
+ pointee_info
+ );
+
+ pointee_info
+ }
+
+ fn is_adt(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Adt(..))
+ }
+
+ fn is_never(this: TyAndLayout<'tcx>) -> bool {
+ this.ty.kind() == &ty::Never
+ }
+
+ fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Tuple(..))
+ }
+
+ fn is_unit(this: TyAndLayout<'tcx>) -> bool {
+ matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
+ }
+}
+
+impl<'tcx> ty::Instance<'tcx> {
+ // NOTE(eddyb) this is private to avoid using it from outside of
+ // `fn_abi_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 `fn_abi_of_instance` might be performing.
+ fn fn_sig_for_fn_abi(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> ty::PolyFnSig<'tcx> {
+ let ty = self.ty(tcx, param_env);
+ match *ty.kind() {
+ ty::FnDef(..) => {
+ // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
+ // parameters unused if they show up in the signature, but not in the `mir::Body`
+ // (i.e. due to being inside a projection that got normalized, see
+ // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
+ // track of a polymorphization `ParamEnv` to allow normalizing later.
+ let mut sig = match *ty.kind() {
+ ty::FnDef(def_id, substs) => tcx
+ .normalize_erasing_regions(tcx.param_env(def_id), tcx.bound_fn_sig(def_id))
+ .subst(tcx, substs),
+ _ => unreachable!(),
+ };
+
+ 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();
+
+ let bound_vars = tcx.mk_bound_variable_kinds(
+ sig.bound_vars()
+ .iter()
+ .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+ );
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind: ty::BoundRegionKind::BrEnv,
+ };
+ let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
+
+ let sig = sig.skip_binder();
+ ty::Binder::bind_with_vars(
+ tcx.mk_fn_sig(
+ iter::once(env_ty).chain(sig.inputs().iter().cloned()),
+ sig.output(),
+ sig.c_variadic,
+ sig.unsafety,
+ sig.abi,
+ ),
+ bound_vars,
+ )
+ }
+ ty::Generator(_, substs, _) => {
+ let sig = substs.as_generator().poly_sig();
+
+ let bound_vars = tcx.mk_bound_variable_kinds(
+ sig.bound_vars()
+ .iter()
+ .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+ );
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind: ty::BoundRegionKind::BrEnv,
+ };
+ let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
+
+ let pin_did = tcx.require_lang_item(LangItem::Pin, None);
+ 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);
+
+ let sig = sig.skip_binder();
+ let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
+ 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);
+ ty::Binder::bind_with_vars(
+ tcx.mk_fn_sig(
+ [env_ty, sig.resume_ty].iter(),
+ &ret_ty,
+ false,
+ hir::Unsafety::Normal,
+ rustc_target::spec::abi::Abi::Rust,
+ ),
+ bound_vars,
+ )
+ }
+ _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
+ }
+ }
+}
+
+/// Calculates whether a function's ABI can unwind or not.
+///
+/// This takes two primary parameters:
+///
+/// * `codegen_fn_attr_flags` - these are flags calculated as part of the
+/// codegen attrs for a defined function. For function pointers this set of
+/// flags is the empty set. This is only applicable for Rust-defined
+/// functions, and generally isn't needed except for small optimizations where
+/// we try to say a function which otherwise might look like it could unwind
+/// doesn't actually unwind (such as for intrinsics and such).
+///
+/// * `abi` - this is the ABI that the function is defined with. This is the
+/// primary factor for determining whether a function can unwind or not.
+///
+/// Note that in this case unwinding is not necessarily panicking in Rust. Rust
+/// panics are implemented with unwinds on most platform (when
+/// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
+/// Notably unwinding is disallowed for more non-Rust ABIs unless it's
+/// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
+/// defined for each ABI individually, but it always corresponds to some form of
+/// stack-based unwinding (the exact mechanism of which varies
+/// platform-by-platform).
+///
+/// Rust functions are classified whether or not they can unwind based on the
+/// active "panic strategy". In other words Rust functions are considered to
+/// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
+/// Note that Rust supports intermingling panic=abort and panic=unwind code, but
+/// only if the final panic mode is panic=abort. In this scenario any code
+/// previously compiled assuming that a function can unwind is still correct, it
+/// just never happens to actually unwind at runtime.
+///
+/// This function's answer to whether or not a function can unwind is quite
+/// impactful throughout the compiler. This affects things like:
+///
+/// * Calling a function which can't unwind means codegen simply ignores any
+/// associated unwinding cleanup.
+/// * Calling a function which can unwind from a function which can't unwind
+/// causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
+/// aborts the process.
+/// * This affects whether functions have the LLVM `nounwind` attribute, which
+/// affects various optimizations and codegen.
+///
+/// FIXME: this is actually buggy with respect to Rust functions. Rust functions
+/// compiled with `-Cpanic=unwind` and referenced from another crate compiled
+/// with `-Cpanic=abort` will look like they can't unwind when in fact they
+/// might (from a foreign exception or similar).
+#[inline]
+pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
+ if let Some(did) = fn_def_id {
+ // Special attribute for functions which can't unwind.
+ if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
+ return false;
+ }
+
+ // With `-C panic=abort`, all non-FFI functions are required to not unwind.
+ //
+ // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
+ // function defined in Rust is also required to abort.
+ if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
+ return false;
+ }
+
+ // With -Z panic-in-drop=abort, drop_in_place never unwinds.
+ //
+ // This is not part of `codegen_fn_attrs` as it can differ between crates
+ // and therefore cannot be computed in core.
+ if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort {
+ if Some(did) == tcx.lang_items().drop_in_place_fn() {
+ return false;
+ }
+ }
+ }
+
+ // Otherwise if this isn't special then unwinding is generally determined by
+ // the ABI of the itself. ABIs like `C` have variants which also
+ // specifically allow unwinding (`C-unwind`), but not all platform-specific
+ // ABIs have such an option. Otherwise the only other thing here is Rust
+ // itself, and those ABIs are determined by the panic strategy configured
+ // for this compilation.
+ //
+ // Unfortunately at this time there's also another caveat. Rust [RFC
+ // 2945][rfc] has been accepted and is in the process of being implemented
+ // and stabilized. In this interim state we need to deal with historical
+ // rustc behavior as well as plan for future rustc behavior.
+ //
+ // Historically functions declared with `extern "C"` were marked at the
+ // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
+ // or not. This is UB for functions in `panic=unwind` mode that then
+ // actually panic and unwind. Note that this behavior is true for both
+ // externally declared functions as well as Rust-defined function.
+ //
+ // To fix this UB rustc would like to change in the future to catch unwinds
+ // from function calls that may unwind within a Rust-defined `extern "C"`
+ // function and forcibly abort the process, thereby respecting the
+ // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't
+ // ready to roll out, so determining whether or not the `C` family of ABIs
+ // unwinds is conditional not only on their definition but also whether the
+ // `#![feature(c_unwind)]` feature gate is active.
+ //
+ // Note that this means that unlike historical compilers rustc now, by
+ // default, unconditionally thinks that the `C` ABI may unwind. This will
+ // prevent some optimization opportunities, however, so we try to scope this
+ // change and only assume that `C` unwinds with `panic=unwind` (as opposed
+ // to `panic=abort`).
+ //
+ // Eventually the check against `c_unwind` here will ideally get removed and
+ // this'll be a little cleaner as it'll be a straightforward check of the
+ // ABI.
+ //
+ // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
+ use SpecAbi::*;
+ match abi {
+ C { unwind }
+ | System { unwind }
+ | Cdecl { unwind }
+ | Stdcall { unwind }
+ | Fastcall { unwind }
+ | Vectorcall { unwind }
+ | Thiscall { unwind }
+ | Aapcs { unwind }
+ | Win64 { unwind }
+ | SysV64 { unwind } => {
+ unwind
+ || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
+ }
+ PtxKernel
+ | Msp430Interrupt
+ | X86Interrupt
+ | AmdGpuKernel
+ | EfiApi
+ | AvrInterrupt
+ | AvrNonBlockingInterrupt
+ | CCmseNonSecureCall
+ | Wasm
+ | RustIntrinsic
+ | PlatformIntrinsic
+ | Unadjusted => false,
+ Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
+ }
+}
+
+#[inline]
+pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
+ use rustc_target::spec::abi::Abi::*;
+ match tcx.sess.target.adjust_abi(abi) {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+ RustCold => Conv::RustCold,
+
+ // 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,
+ CCmseNonSecureCall => Conv::CCmseNonSecureCall,
+ PtxKernel => Conv::PtxKernel,
+ Msp430Interrupt => Conv::Msp430Intr,
+ X86Interrupt => Conv::X86Intr,
+ AmdGpuKernel => Conv::AmdGpuKernel,
+ AvrInterrupt => Conv::AvrInterrupt,
+ AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+ Wasm => Conv::C,
+
+ // These API constants ought to be more specific...
+ Cdecl { .. } => Conv::C,
+ }
+}
+
+/// Error produced by attempting to compute or adjust a `FnAbi`.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum FnAbiError<'tcx> {
+ /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
+ Layout(LayoutError<'tcx>),
+
+ /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
+ AdjustForForeignAbi(call::AdjustForForeignAbiError),
+}
+
+impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
+ fn from(err: LayoutError<'tcx>) -> Self {
+ Self::Layout(err)
+ }
+}
+
+impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
+ fn from(err: call::AdjustForForeignAbiError) -> Self {
+ Self::AdjustForForeignAbi(err)
+ }
+}
+
+impl<'tcx> fmt::Display for FnAbiError<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Layout(err) => err.fmt(f),
+ Self::AdjustForForeignAbi(err) => err.fmt(f),
+ }
+ }
+}
+
+// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
+// just for error handling.
+#[derive(Debug)]
+pub enum FnAbiRequest<'tcx> {
+ OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+ OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+}
+
+/// Trait for contexts that want to be able to compute `FnAbi`s.
+/// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
+pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
+ /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
+ /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
+ type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
+
+ /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
+ /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
+ ///
+ /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
+ /// but this hook allows e.g. codegen to return only `&FnAbi` from its
+ /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
+ /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
+ fn handle_fn_abi_err(
+ &self,
+ err: FnAbiError<'tcx>,
+ span: Span,
+ fn_abi_request: FnAbiRequest<'tcx>,
+ ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
+}
+
+/// Blanket extension trait for contexts that can compute `FnAbi`s.
+pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
+ /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+ ///
+ /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+ /// instead, where the instance is an `InstanceDef::Virtual`.
+ #[inline]
+ fn fn_abi_of_fn_ptr(
+ &self,
+ sig: ty::PolyFnSig<'tcx>,
+ extra_args: &'tcx ty::List<Ty<'tcx>>,
+ ) -> Self::FnAbiOfResult {
+ // FIXME(eddyb) get a better `span` here.
+ let span = self.layout_tcx_at_span();
+ let tcx = self.tcx().at(span);
+
+ MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
+ |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
+ ))
+ }
+
+ /// 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 an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+ #[inline]
+ fn fn_abi_of_instance(
+ &self,
+ instance: ty::Instance<'tcx>,
+ extra_args: &'tcx ty::List<Ty<'tcx>>,
+ ) -> Self::FnAbiOfResult {
+ // FIXME(eddyb) get a better `span` here.
+ let span = self.layout_tcx_at_span();
+ let tcx = self.tcx().at(span);
+
+ MaybeResult::from(
+ tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
+ // HACK(eddyb) at least for definitions of/calls to `Instance`s,
+ // we can get some kind of span even if one wasn't provided.
+ // However, we don't do this early in order to avoid calling
+ // `def_span` unconditionally (which may have a perf penalty).
+ let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
+ self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
+ }),
+ )
+ }
+}
+
+impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
+
+fn fn_abi_of_fn_ptr<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+ let (param_env, (sig, extra_args)) = query.into_parts();
+
+ LayoutCx { tcx, param_env }.fn_abi_new_uncached(sig, extra_args, None, None, false)
+}
+
+fn fn_abi_of_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+ let (param_env, (instance, extra_args)) = query.into_parts();
+
+ let sig = instance.fn_sig_for_fn_abi(tcx, param_env);
+
+ let caller_location = if instance.def.requires_caller_location(tcx) {
+ Some(tcx.caller_location_ty())
+ } else {
+ None
+ };
+
+ LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+ sig,
+ extra_args,
+ caller_location,
+ Some(instance.def_id()),
+ matches!(instance.def, ty::InstanceDef::Virtual(..)),
+ )
+}
+
+impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
+ // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
+ // arguments of this method, into a separate `struct`.
+ fn fn_abi_new_uncached(
+ &self,
+ sig: ty::PolyFnSig<'tcx>,
+ extra_args: &[Ty<'tcx>],
+ caller_location: Option<Ty<'tcx>>,
+ fn_def_id: Option<DefId>,
+ // FIXME(eddyb) replace this with something typed, like an `enum`.
+ force_thin_self_ptr: bool,
+ ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+ debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args);
+
+ let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
+
+ let conv = conv_from_spec_abi(self.tcx(), sig.abi);
+
+ 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
+ } 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
+ };
+
+ let target = &self.tcx.sess.target;
+ let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
+ let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
+ let linux_s390x_gnu_like =
+ target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
+ let linux_sparc64_gnu_like =
+ target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
+ let linux_powerpc_gnu_like =
+ target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+ use SpecAbi::*;
+ let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
+
+ // Handle safe Rust thin and fat pointers.
+ let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
+ scalar: Scalar,
+ layout: TyAndLayout<'tcx>,
+ offset: Size,
+ is_return: bool| {
+ // Booleans are always a noundef i1 that needs to be zero-extended.
+ if scalar.is_bool() {
+ attrs.ext(ArgExtension::Zext);
+ attrs.set(ArgAttribute::NoUndef);
+ return;
+ }
+
+ // Scalars which have invalid values cannot be undef.
+ if !scalar.is_always_valid(self) {
+ attrs.set(ArgAttribute::NoUndef);
+ }
+
+ // Only pointer types handled below.
+ let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
+
+ if !valid_range.contains(0) {
+ attrs.set(ArgAttribute::NonNull);
+ }
+
+ if let Some(pointee) = layout.pointee_info_at(self, offset) {
+ if let Some(kind) = pointee.safe {
+ attrs.pointee_align = Some(pointee.align);
+
+ // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
+ // for the entire duration of the function as they can be deallocated
+ // at any time. Same for shared mutable references. If LLVM had a
+ // way to say "dereferenceable on entry" we could use it here.
+ attrs.pointee_size = match kind {
+ PointerKind::UniqueBorrowed
+ | PointerKind::UniqueBorrowedPinned
+ | PointerKind::Frozen => pointee.size,
+ PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+ };
+
+ // `Box`, `&T`, and `&mut T` cannot be undef.
+ // Note that this only applies to the value of the pointer itself;
+ // this attribute doesn't make it UB for the pointed-to data to be undef.
+ attrs.set(ArgAttribute::NoUndef);
+
+ // The aliasing rules for `Box<T>` are still not decided, but currently we emit
+ // `noalias` for it. This can be turned off using an unstable flag.
+ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
+ let noalias_for_box =
+ self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+
+ // `&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
+ //
+ // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+ // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled with the
+ // `-Zmutable-noalias` debugging option.
+ let no_alias = match kind {
+ PointerKind::SharedMutable
+ | PointerKind::UniqueBorrowed
+ | PointerKind::UniqueBorrowedPinned => false,
+ PointerKind::UniqueOwned => noalias_for_box,
+ PointerKind::Frozen => !is_return,
+ };
+ if no_alias {
+ attrs.set(ArgAttribute::NoAlias);
+ }
+
+ if kind == PointerKind::Frozen && !is_return {
+ attrs.set(ArgAttribute::ReadOnly);
+ }
+
+ if kind == PointerKind::UniqueBorrowed && !is_return {
+ attrs.set(ArgAttribute::NoAliasMutRef);
+ }
+ }
+ }
+ };
+
+ let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
+ let is_return = arg_idx.is_none();
+
+ let layout = self.layout_of(ty)?;
+ let layout = if force_thin_self_ptr && arg_idx == Some(0) {
+ // 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
+ make_thin_self_ptr(self, layout)
+ } else {
+ layout
+ };
+
+ let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
+ let mut attrs = ArgAttributes::new();
+ adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
+ attrs
+ });
+
+ 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,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}.
+ if is_return
+ || rust_abi
+ || (!win_x64_gnu
+ && !linux_s390x_gnu_like
+ && !linux_sparc64_gnu_like
+ && !linux_powerpc_gnu_like)
+ {
+ arg.mode = PassMode::Ignore;
+ }
+ }
+
+ Ok(arg)
+ };
+
+ let mut fn_abi = FnAbi {
+ ret: arg_of(sig.output(), None)?,
+ args: inputs
+ .iter()
+ .copied()
+ .chain(extra_args.iter().copied())
+ .chain(caller_location)
+ .enumerate()
+ .map(|(i, ty)| arg_of(ty, Some(i)))
+ .collect::<Result<_, _>>()?,
+ c_variadic: sig.c_variadic,
+ fixed_count: inputs.len(),
+ conv,
+ can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi),
+ };
+ self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
+ debug!("fn_abi_new_uncached = {:?}", fn_abi);
+ Ok(self.tcx.arena.alloc(fn_abi))
+ }
+
+ fn fn_abi_adjust_for_abi(
+ &self,
+ fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
+ abi: SpecAbi,
+ ) -> Result<(), FnAbiError<'tcx>> {
+ if abi == SpecAbi::Unadjusted {
+ return Ok(());
+ }
+
+ 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
+ && self.tcx.sess.target.simd_types_indirect =>
+ {
+ arg.make_indirect();
+ return;
+ }
+
+ _ => return,
+ }
+
+ let size = arg.layout.size;
+ if arg.layout.is_unsized() || size > Pointer.size(self) {
+ 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 fn_abi.ret);
+ for arg in &mut fn_abi.args {
+ fixup(arg);
+ }
+ } else {
+ fn_abi.adjust_for_foreign_abi(self, abi)?;
+ }
+
+ Ok(())
+ }
+}
+
+fn make_thin_self_ptr<'tcx>(
+ cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
+ layout: TyAndLayout<'tcx>,
+) -> TyAndLayout<'tcx> {
+ let tcx = cx.tcx();
+ 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
+ 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_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit());
+
+ TyAndLayout {
+ ty: fat_pointer_ty,
+
+ // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
+ // should always work because the type is always `*mut ()`.
+ ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
new file mode 100644
index 000000000..db3b5cfd1
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -0,0 +1,215 @@
+use crate::arena::Arena;
+use rustc_serialize::{Encodable, Encoder};
+use std::alloc::Layout;
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::iter;
+use std::mem;
+use std::ops::Deref;
+use std::ptr;
+use std::slice;
+
+/// `List<T>` is a bit like `&[T]`, but with some critical differences.
+/// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The
+/// type's correctness relies on this, *but it does not enforce it*.
+/// Therefore, any code that creates a `List<T>` must ensure uniqueness
+/// itself. In practice this is achieved by interning.
+/// - The length is stored within the `List<T>`, so `&List<Ty>` is a thin
+/// pointer.
+/// - Because of this, you cannot get a `List<T>` that is a sub-list of another
+/// `List<T>`. You can get a sub-slice `&[T]`, however.
+/// - `List<T>` can be used with `CopyTaggedPtr`, which is useful within
+/// structs whose size must be minimized.
+/// - Because of the uniqueness assumption, we can use the address of a
+/// `List<T>` for faster equality comparisons and hashing.
+/// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and
+/// iterators return a `T` rather than a `&T`.
+/// - `T` must not be zero-sized.
+#[repr(C)]
+pub struct List<T> {
+ len: usize,
+
+ /// Although this claims to be a zero-length array, in practice `len`
+ /// elements are actually present.
+ data: [T; 0],
+
+ opaque: OpaqueListContents,
+}
+
+extern "C" {
+ /// A dummy type used to force `List` to be unsized while not requiring
+ /// references to it be wide pointers.
+ type OpaqueListContents;
+}
+
+impl<T> List<T> {
+ /// Returns a reference to the (unique, static) empty list.
+ #[inline(always)]
+ pub fn empty<'a>() -> &'a List<T> {
+ #[repr(align(64))]
+ struct MaxAlign;
+
+ assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>());
+
+ #[repr(C)]
+ struct InOrder<T, U>(T, U);
+
+ // The empty slice is static and contains a single `0` usize (for the
+ // length) that is 64-byte aligned, thus featuring the necessary
+ // trailing padding for elements with up to 64-byte alignment.
+ static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
+ unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+ }
+
+ pub fn len(&self) -> usize {
+ self.len
+ }
+}
+
+impl<T: Copy> List<T> {
+ /// Allocates a list from `arena` and copies the contents of `slice` into it.
+ ///
+ /// WARNING: the contents *must be unique*, such that no list with these
+ /// contents has been previously created. If not, operations such as `eq`
+ /// and `hash` might give incorrect results.
+ ///
+ /// Panics if `T` is `Drop`, or `T` is zero-sized, or the slice is empty
+ /// (because the empty list exists statically, and is available via
+ /// `empty()`).
+ #[inline]
+ pub(super) 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.is_empty());
+
+ let (layout, _offset) =
+ Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
+ let mem = arena.dropless.alloc_raw(layout) as *mut List<T>;
+ unsafe {
+ // Write the length
+ ptr::addr_of_mut!((*mem).len).write(slice.len());
+
+ // Write the elements
+ ptr::addr_of_mut!((*mem).data)
+ .cast::<T>()
+ .copy_from_nonoverlapping(slice.as_ptr(), slice.len());
+
+ &*mem
+ }
+ }
+
+ // If this method didn't exist, we would use `slice.iter` due to
+ // deref coercion.
+ //
+ // This would be weird, as `self.into_iter` iterates over `T` directly.
+ #[inline(always)]
+ pub fn iter(&self) -> <&'_ List<T> as IntoIterator>::IntoIter {
+ self.into_iter()
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for List<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (**self).fmt(f)
+ }
+}
+
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
+ #[inline]
+ fn encode(&self, s: &mut S) {
+ (**self).encode(s);
+ }
+}
+
+impl<T: PartialEq> PartialEq for List<T> {
+ #[inline]
+ fn eq(&self, other: &List<T>) -> bool {
+ // Pointer equality implies list equality (due to the unique contents
+ // assumption).
+ ptr::eq(self, other)
+ }
+}
+
+impl<T: Eq> Eq for List<T> {}
+
+impl<T> Ord for List<T>
+where
+ T: Ord,
+{
+ fn cmp(&self, other: &List<T>) -> Ordering {
+ // Pointer equality implies list equality (due to the unique contents
+ // assumption), but the contents must be compared otherwise.
+ 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> {
+ // Pointer equality implies list equality (due to the unique contents
+ // assumption), but the contents must be compared otherwise.
+ if self == other {
+ Some(Ordering::Equal)
+ } else {
+ <[T] as PartialOrd>::partial_cmp(&**self, &**other)
+ }
+ }
+}
+
+impl<T> Hash for List<T> {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // Pointer hashing is sufficient (due to the unique contents
+ // assumption).
+ (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: Copy> IntoIterator for &'a List<T> {
+ type Item = T;
+ type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>;
+ #[inline(always)]
+ fn into_iter(self) -> Self::IntoIter {
+ self[..].iter().copied()
+ }
+}
+
+unsafe impl<T: Sync> Sync for List<T> {}
+
+unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
+ const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+
+ #[inline]
+ fn into_usize(self) -> usize {
+ self as *const List<T> as usize
+ }
+
+ #[inline]
+ unsafe fn from_usize(ptr: usize) -> &'a List<T> {
+ &*(ptr as *const List<T>)
+ }
+
+ unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
+ // `Self` is `&'a List<T>` which impls `Copy`, so this is fine.
+ let ptr = Self::from_usize(ptr);
+ f(&ptr)
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
new file mode 100644
index 000000000..02da02568
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -0,0 +1,2518 @@
+//! Defines how the compiler represents types internally.
+//!
+//! Two important entities in this module are:
+//!
+//! - [`rustc_middle::ty::Ty`], used to represent the semantics of a type.
+//! - [`rustc_middle::ty::TyCtxt`], the central data structure in the compiler.
+//!
+//! For more information, see ["The `ty` module: representing types"] in the rustc-dev-guide.
+//!
+//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
+
+pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+pub use self::AssocItemContainer::*;
+pub use self::BorrowKind::*;
+pub use self::IntVarValue::*;
+pub use self::Variance::*;
+use crate::metadata::ModChild;
+use crate::middle::privacy::AccessLevels;
+use crate::mir::{Body, GeneratorLayout};
+use crate::traits::{self, Reveal};
+use crate::ty;
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::util::Discr;
+pub use adt::*;
+pub use assoc::*;
+pub use generics::*;
+use rustc_ast as ast;
+use rustc_ast::node_id::NodeMap;
+use rustc_attr as attr;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::intern::{Interned, WithStableHash};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
+use rustc_hir as hir;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
+use rustc_hir::Node;
+use rustc_index::vec::IndexVec;
+use rustc_macros::HashStable;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_span::hygiene::MacroKind;
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{ExpnId, Span};
+use rustc_target::abi::{Align, VariantIdx};
+pub use subst::*;
+pub use vtable::*;
+
+use std::fmt::Debug;
+use std::hash::{Hash, Hasher};
+use std::ops::ControlFlow;
+use std::{fmt, str};
+
+pub use crate::ty::diagnostics::*;
+pub use rustc_type_ir::InferTy::*;
+pub use rustc_type_ir::RegionKind::*;
+pub use rustc_type_ir::TyKind::*;
+pub use rustc_type_ir::*;
+
+pub use self::binding::BindingMode;
+pub use self::binding::BindingMode::*;
+pub use self::closure::{
+ is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
+ CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList,
+ RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
+ CAPTURE_STRUCT_LOCAL,
+};
+pub use self::consts::{
+ Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree,
+};
+pub use self::context::{
+ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
+ CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+ GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
+ UserTypeAnnotationIndex,
+};
+pub use self::instance::{Instance, InstanceDef};
+pub use self::list::List;
+pub use self::parameterized::ParameterizedOverTcx;
+pub use self::rvalue_scopes::RvalueScopes;
+pub use self::sty::BoundRegionKind::*;
+pub use self::sty::{
+ Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
+ BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
+ EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection,
+ ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts,
+ InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
+ PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
+ RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
+};
+pub use self::trait_def::TraitDef;
+
+pub mod _match;
+pub mod abstract_const;
+pub mod adjustment;
+pub mod binding;
+pub mod cast;
+pub mod codec;
+pub mod error;
+pub mod fast_reject;
+pub mod flags;
+pub mod fold;
+pub mod inhabitedness;
+pub mod layout;
+pub mod normalize_erasing_regions;
+pub mod print;
+pub mod query;
+pub mod relate;
+pub mod subst;
+pub mod trait_def;
+pub mod util;
+pub mod visit;
+pub mod vtable;
+pub mod walk;
+
+mod adt;
+mod assoc;
+mod closure;
+mod consts;
+mod context;
+mod diagnostics;
+mod erase_regions;
+mod generics;
+mod impls_ty;
+mod instance;
+mod list;
+mod parameterized;
+mod rvalue_scopes;
+mod structural_impls;
+mod sty;
+
+// Data types
+
+pub type RegisteredTools = FxHashSet<Ident>;
+
+#[derive(Debug)]
+pub struct ResolverOutputs {
+ pub visibilities: FxHashMap<LocalDefId, Visibility>,
+ /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
+ pub has_pub_restricted: bool,
+ /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
+ pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
+ /// Reference span for definitions.
+ pub source_span: IndexVec<LocalDefId, Span>,
+ pub access_levels: AccessLevels,
+ pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
+ pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
+ pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
+ pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
+ pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
+ /// 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<Symbol, bool>,
+ pub main_def: Option<MainDefinition>,
+ pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
+ /// A list of proc macro LocalDefIds, written out in the order in which
+ /// they are declared in the static array generated by proc_macro_harness.
+ pub proc_macros: Vec<LocalDefId>,
+ /// Mapping from ident span to path span for paths that don't exist as written, but that
+ /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
+ pub confused_type_with_std_module: FxHashMap<Span, Span>,
+ pub registered_tools: RegisteredTools,
+}
+
+/// Resolutions that should only be used for lowering.
+/// This struct is meant to be consumed by lowering.
+#[derive(Debug)]
+pub struct ResolverAstLowering {
+ pub legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
+
+ /// Resolutions for nodes that have a single resolution.
+ pub partial_res_map: NodeMap<hir::def::PartialRes>,
+ /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
+ pub import_res_map: NodeMap<hir::def::PerNS<Option<Res<ast::NodeId>>>>,
+ /// Resolutions for labels (node IDs of their corresponding blocks or loops).
+ pub label_res_map: NodeMap<ast::NodeId>,
+ /// Resolutions for lifetimes.
+ pub lifetimes_res_map: NodeMap<LifetimeRes>,
+ /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+ /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+ /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+ /// field from the original parameter 'a to the new parameter 'a1.
+ pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
+ /// Lifetime parameters that lowering will have to introduce.
+ pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
+
+ pub next_node_id: ast::NodeId,
+
+ pub node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+ pub def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
+
+ pub trait_map: NodeMap<Vec<hir::TraitCandidate>>,
+ /// A small map keeping true kinds of built-in macros that appear to be fn-like on
+ /// the surface (`macro` items in libcore), but are actually attributes or derives.
+ pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct MainDefinition {
+ pub res: Res<ast::NodeId>,
+ pub is_import: bool,
+ pub span: Span,
+}
+
+impl MainDefinition {
+ pub fn opt_fn_def_id(self) -> Option<DefId> {
+ if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None }
+ }
+}
+
+/// 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, TypeVisitable)]
+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, Debug, TypeFoldable, TypeVisitable)]
+pub enum ImplSubject<'tcx> {
+ Trait(TraitRef<'tcx>),
+ Inherent(Ty<'tcx>),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(TypeFoldable, TypeVisitable)]
+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,
+}
+
+impl ImplPolarity {
+ /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
+ pub fn flip(&self) -> Option<ImplPolarity> {
+ match self {
+ ImplPolarity::Positive => Some(ImplPolarity::Negative),
+ ImplPolarity::Negative => Some(ImplPolarity::Positive),
+ ImplPolarity::Reservation => None,
+ }
+ }
+}
+
+impl fmt::Display for ImplPolarity {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Positive => f.write_str("positive"),
+ Self::Negative => f.write_str("negative"),
+ Self::Reservation => f.write_str("reservation"),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, 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,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
+pub enum BoundConstness {
+ /// `T: Trait`
+ NotConst,
+ /// `T: ~const Trait`
+ ///
+ /// Requires resolving to const only when we are in a const context.
+ ConstIfConst,
+}
+
+impl BoundConstness {
+ /// Reduce `self` and `constness` to two possible combined states instead of four.
+ pub fn and(&mut self, constness: hir::Constness) -> hir::Constness {
+ match (constness, self) {
+ (hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const,
+ (_, this) => {
+ *this = BoundConstness::NotConst;
+ hir::Constness::NotConst
+ }
+ }
+ }
+}
+
+impl fmt::Display for BoundConstness {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::NotConst => f.write_str("normal"),
+ Self::ConstIfConst => f.write_str("`~const`"),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct ClosureSizeProfileData<'tcx> {
+ /// Tuple containing the types of closure captures before the feature `capture_disjoint_fields`
+ pub before_feature_tys: Ty<'tcx>,
+ /// Tuple containing the types of closure captures after the feature `capture_disjoint_fields`
+ pub after_feature_tys: Ty<'tcx>,
+}
+
+pub trait DefIdTree: Copy {
+ fn opt_parent(self, id: DefId) -> Option<DefId>;
+
+ #[inline]
+ #[track_caller]
+ fn parent(self, id: DefId) -> DefId {
+ match self.opt_parent(id) {
+ Some(id) => id,
+ // not `unwrap_or_else` to avoid breaking caller tracking
+ None => bug!("{id:?} doesn't have a parent"),
+ }
+ }
+
+ #[inline]
+ #[track_caller]
+ fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
+ self.opt_parent(id.to_def_id()).map(DefId::expect_local)
+ }
+
+ #[inline]
+ #[track_caller]
+ fn local_parent(self, id: LocalDefId) -> LocalDefId {
+ self.parent(id.to_def_id()).expect_local()
+ }
+
+ fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
+ if descendant.krate != ancestor.krate {
+ return false;
+ }
+
+ while descendant != ancestor {
+ match self.opt_parent(descendant) {
+ Some(parent) => descendant = parent,
+ None => return false,
+ }
+ }
+ true
+ }
+}
+
+impl<'tcx> DefIdTree for TyCtxt<'tcx> {
+ #[inline]
+ fn opt_parent(self, id: DefId) -> Option<DefId> {
+ self.def_key(id).parent.map(|index| DefId { index, ..id })
+ }
+}
+
+impl Visibility {
+ /// 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,
+ }
+ }
+
+ pub fn is_public(self) -> bool {
+ matches!(self, Visibility::Public)
+ }
+}
+
+/// 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, Debug)]
+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]>,
+}
+
+// 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: Option<CrateNum>,
+ pub pos: usize,
+}
+
+/// Represents a type.
+///
+/// IMPORTANT:
+/// - This is a very "dumb" struct (with no derives and no `impls`).
+/// - Values of this type are always interned and thus unique, and are stored
+/// as an `Interned<TyS>`.
+/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>`
+/// should be used everywhere instead of `TyS`. In particular, `Ty` has most
+/// of the relevant methods.
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[allow(rustc::usage_of_ty_tykind)]
+pub(crate) struct TyS<'tcx> {
+ /// This field shouldn't be used directly and may be removed in the future.
+ /// Use `Ty::kind()` instead.
+ kind: TyKind<'tcx>,
+
+ /// This field provides fast access to information that is also contained
+ /// in `kind`.
+ ///
+ /// This field shouldn't be used directly and may be removed in the future.
+ /// Use `Ty::flags()` instead.
+ flags: TypeFlags,
+
+ /// This field provides fast access to information that is also contained
+ /// in `kind`.
+ ///
+ /// 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(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(TyS<'_>, 40);
+
+// We are actually storing a stable hash cache next to the type, so let's
+// also check the full size
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(WithStableHash<TyS<'_>>, 56);
+
+/// Use this rather than `TyS`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[rustc_diagnostic_item = "Ty"]
+#[rustc_pass_by_value]
+pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>);
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// A "bool" type used in rustc_mir_transform unit tests when we
+ /// have not spun up a TyCtxt.
+ pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash {
+ internee: TyS {
+ kind: ty::Bool,
+ flags: TypeFlags::empty(),
+ outer_exclusive_binder: DebruijnIndex::from_usize(0),
+ },
+ stable_hash: Fingerprint::ZERO,
+ }));
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ let TyS {
+ 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)
+ }
+}
+
+impl ty::EarlyBoundRegion {
+ /// 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
+ }
+}
+
+/// Represents a predicate.
+///
+/// See comments on `TyS`, which apply here too (albeit for
+/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`).
+#[derive(Debug)]
+pub(crate) struct PredicateS<'tcx> {
+ kind: Binder<'tcx, PredicateKind<'tcx>>,
+ flags: TypeFlags,
+ /// See the comment for the corresponding field of [TyS].
+ outer_exclusive_binder: ty::DebruijnIndex,
+}
+
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(PredicateS<'_>, 56);
+
+/// Use this rather than `PredicateS`, whenever possible.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[rustc_pass_by_value]
+pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>);
+
+impl<'tcx> Predicate<'tcx> {
+ /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
+ #[inline]
+ pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
+ self.0.kind
+ }
+
+ #[inline(always)]
+ pub fn flags(self) -> TypeFlags {
+ self.0.flags
+ }
+
+ #[inline(always)]
+ pub fn outer_exclusive_binder(self) -> DebruijnIndex {
+ self.0.outer_exclusive_binder
+ }
+
+ /// Flips the polarity of a Predicate.
+ ///
+ /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+ pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
+ let kind = self
+ .kind()
+ .map_bound(|kind| match kind {
+ PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
+ Some(PredicateKind::Trait(TraitPredicate {
+ trait_ref,
+ constness,
+ polarity: polarity.flip()?,
+ }))
+ }
+
+ _ => None,
+ })
+ .transpose()?;
+
+ Some(tcx.mk_predicate(kind))
+ }
+
+ pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
+ if let PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) = self.kind().skip_binder()
+ && constness != BoundConstness::NotConst
+ {
+ self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Trait(TraitPredicate {
+ trait_ref,
+ constness: BoundConstness::NotConst,
+ polarity,
+ })));
+ }
+ self
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ let PredicateS {
+ 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.0.0;
+
+ kind.hash_stable(hcx, hasher);
+ }
+}
+
+impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub enum PredicateKind<'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.
+ Trait(TraitPredicate<'tcx>),
+
+ /// `where 'a: 'b`
+ RegionOutlives(RegionOutlivesPredicate<'tcx>),
+
+ /// `where T: 'a`
+ TypeOutlives(TypeOutlivesPredicate<'tcx>),
+
+ /// `where <T as TraitRef>::Name == X`, approximately.
+ /// See the `ProjectionPredicate` struct for details.
+ Projection(ProjectionPredicate<'tcx>),
+
+ /// No syntax: `T` well-formed.
+ WellFormed(GenericArg<'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`
+ ///
+ /// This obligation is created most often when we have two
+ /// unresolved type variables and hence don't have enough
+ /// information to process the subtyping obligation yet.
+ Subtype(SubtypePredicate<'tcx>),
+
+ /// `T1` coerced to `T2`
+ ///
+ /// Like a subtyping obligation, this is created most often
+ /// when we have two unresolved type variables and hence
+ /// don't have enough information to process the coercion
+ /// obligation yet. At the moment, we actually process coercions
+ /// very much like subtyping and don't handle the full coercion
+ /// logic.
+ Coerce(CoercePredicate<'tcx>),
+
+ /// Constant initializer must evaluate successfully.
+ ConstEvaluatable(ty::Unevaluated<'tcx, ()>),
+
+ /// Constants must be equal. The first component is the const that is expected.
+ ConstEquate(Const<'tcx>, Const<'tcx>),
+
+ /// Represents a type found in the environment that we can use for implied bounds.
+ ///
+ /// Only used for Chalk.
+ TypeWellFormedFromEnv(Ty<'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, Debug)]
+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 [(Predicate<'tcx>, Span)]>,
+}
+
+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>,
+ ) -> 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 supertrait-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).
+
+ // Working through the second example:
+ // trait_ref: for<'x> T: Foo1<'^0.0>; substs: [T, '^0.0]
+ // predicate: for<'b> Self: Bar1<'a, '^0.0>; substs: [Self, 'a, '^0.0]
+ // We want to end up with:
+ // for<'x, 'b> T: Bar1<'^0.0, '^0.1>
+ // To do this:
+ // 1) We must shift all bound vars in predicate by the length
+ // of trait ref's bound vars. So, we would end up with predicate like
+ // Self: Bar1<'a, '^0.1>
+ // 2) We can then apply the trait substs to this, ending up with
+ // T: Bar1<'^0.0, '^0.1>
+ // 3) Finally, to create the final bound vars, we concatenate the bound
+ // vars of the trait ref with those of the predicate:
+ // ['x, 'b]
+ let bound_pred = self.kind();
+ let pred_bound_vars = bound_pred.bound_vars();
+ let trait_bound_vars = trait_ref.bound_vars();
+ // 1) Self: Bar1<'a, '^0.0> -> Self: Bar1<'a, '^0.1>
+ let shifted_pred =
+ tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder());
+ // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1>
+ let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
+ // 3) ['x] + ['b] -> ['x, 'b]
+ let bound_vars =
+ tcx.mk_bound_variable_kinds(trait_bound_vars.iter().chain(pred_bound_vars));
+ tcx.reuse_or_mk_predicate(self, ty::Binder::bind_with_vars(new, bound_vars))
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct TraitPredicate<'tcx> {
+ pub trait_ref: TraitRef<'tcx>,
+
+ pub constness: BoundConstness,
+
+ /// If polarity is Positive: we are proving that the trait is implemented.
+ ///
+ /// If polarity is Negative: we are proving that a negative impl of this trait
+ /// exists. (Note that coherence also checks whether negative impls of supertraits
+ /// exist via a series of predicates.)
+ ///
+ /// If polarity is Reserved: that's a bug.
+ pub polarity: ImplPolarity,
+}
+
+pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
+
+impl<'tcx> TraitPredicate<'tcx> {
+ pub fn remap_constness(&mut self, param_env: &mut ParamEnv<'tcx>) {
+ *param_env = param_env.with_constness(self.constness.and(param_env.constness()))
+ }
+
+ /// Remap the constness of this predicate before emitting it for diagnostics.
+ pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
+ // this is different to `remap_constness` that callees want to print this predicate
+ // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the
+ // param_env is not const because it is always satisfied in non-const contexts.
+ if let hir::Constness::NotConst = param_env.constness() {
+ self.constness = ty::BoundConstness::NotConst;
+ }
+ }
+
+ pub fn def_id(self) -> DefId {
+ self.trait_ref.def_id
+ }
+
+ pub fn self_ty(self) -> Ty<'tcx> {
+ self.trait_ref.self_ty()
+ }
+
+ #[inline]
+ pub fn is_const_if_const(self) -> bool {
+ self.constness == BoundConstness::ConstIfConst
+ }
+
+ pub fn is_constness_satisfied_by(self, constness: hir::Constness) -> bool {
+ match (self.constness, constness) {
+ (BoundConstness::NotConst, _)
+ | (BoundConstness::ConstIfConst, hir::Constness::Const) => true,
+ (BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
+ }
+ }
+}
+
+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()
+ }
+
+ pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> {
+ self.map_bound(|trait_ref| trait_ref.self_ty())
+ }
+
+ /// Remap the constness of this predicate before emitting it for diagnostics.
+ pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
+ *self = self.map_bound(|mut p| {
+ p.remap_constness_diag(param_env);
+ p
+ });
+ }
+
+ #[inline]
+ pub fn is_const_if_const(self) -> bool {
+ self.skip_binder().is_const_if_const()
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct OutlivesPredicate<A, B>(pub A, pub B); // `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<'tcx, RegionOutlivesPredicate<'tcx>>;
+pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
+
+/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
+/// whether the `a` type is the type that we should label as "expected" when
+/// presenting user diagnostics.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct SubtypePredicate<'tcx> {
+ pub a_is_expected: bool,
+ pub a: Ty<'tcx>,
+ pub b: Ty<'tcx>,
+}
+pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
+
+/// Encodes that we have to coerce *from* the `a` type to the `b` type.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct CoercePredicate<'tcx> {
+ pub a: Ty<'tcx>,
+ pub b: Ty<'tcx>,
+}
+pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub enum Term<'tcx> {
+ Ty(Ty<'tcx>),
+ Const(Const<'tcx>),
+}
+
+impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
+ fn from(ty: Ty<'tcx>) -> Self {
+ Term::Ty(ty)
+ }
+}
+
+impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
+ fn from(c: Const<'tcx>) -> Self {
+ Term::Const(c)
+ }
+}
+
+impl<'tcx> Term<'tcx> {
+ pub fn ty(&self) -> Option<Ty<'tcx>> {
+ if let Term::Ty(ty) = self { Some(*ty) } else { None }
+ }
+
+ pub fn ct(&self) -> Option<Const<'tcx>> {
+ if let Term::Const(c) = self { Some(*c) } else { None }
+ }
+
+ pub fn into_arg(self) -> GenericArg<'tcx> {
+ match self {
+ Term::Ty(ty) => ty.into(),
+ Term::Const(c) => c.into(),
+ }
+ }
+}
+
+/// 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct ProjectionPredicate<'tcx> {
+ pub projection_ty: ProjectionTy<'tcx>,
+ pub term: Term<'tcx>,
+}
+
+pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
+
+impl<'tcx> PolyProjectionPredicate<'tcx> {
+ /// Returns the `DefId` of the trait of the associated item being projected.
+ #[inline]
+ pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+ self.skip_binder().projection_ty.trait_def_id(tcx)
+ }
+
+ /// Get the [PolyTraitRef] required for this projection to be well formed.
+ /// Note that for generic associated types the predicates of the associated
+ /// type also need to be checked.
+ #[inline]
+ pub fn required_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 term(&self) -> Binder<'tcx, Term<'tcx>> {
+ self.map_bound(|predicate| predicate.term)
+ }
+
+ /// 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 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, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>;
+}
+
+impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
+ #[inline(always)]
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ tcx.mk_predicate(self)
+ }
+}
+
+impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ self.map_bound(PredicateKind::Trait).to_predicate(tcx)
+ }
+}
+
+impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ self.map_bound(PredicateKind::RegionOutlives).to_predicate(tcx)
+ }
+}
+
+impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ self.map_bound(PredicateKind::TypeOutlives).to_predicate(tcx)
+ }
+}
+
+impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ self.map_bound(PredicateKind::Projection).to_predicate(tcx)
+ }
+}
+
+impl<'tcx> Predicate<'tcx> {
+ pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
+ let predicate = self.kind();
+ match predicate.skip_binder() {
+ PredicateKind::Trait(t) => Some(predicate.rebind(t)),
+ PredicateKind::Projection(..)
+ | PredicateKind::Subtype(..)
+ | PredicateKind::Coerce(..)
+ | PredicateKind::RegionOutlives(..)
+ | PredicateKind::WellFormed(..)
+ | PredicateKind::ObjectSafe(..)
+ | PredicateKind::ClosureKind(..)
+ | PredicateKind::TypeOutlives(..)
+ | PredicateKind::ConstEvaluatable(..)
+ | PredicateKind::ConstEquate(..)
+ | PredicateKind::TypeWellFormedFromEnv(..) => None,
+ }
+ }
+
+ pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> {
+ let predicate = self.kind();
+ match predicate.skip_binder() {
+ PredicateKind::Projection(t) => Some(predicate.rebind(t)),
+ PredicateKind::Trait(..)
+ | PredicateKind::Subtype(..)
+ | PredicateKind::Coerce(..)
+ | PredicateKind::RegionOutlives(..)
+ | PredicateKind::WellFormed(..)
+ | PredicateKind::ObjectSafe(..)
+ | PredicateKind::ClosureKind(..)
+ | PredicateKind::TypeOutlives(..)
+ | PredicateKind::ConstEvaluatable(..)
+ | PredicateKind::ConstEquate(..)
+ | PredicateKind::TypeWellFormedFromEnv(..) => None,
+ }
+ }
+
+ pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
+ let predicate = self.kind();
+ match predicate.skip_binder() {
+ PredicateKind::TypeOutlives(data) => Some(predicate.rebind(data)),
+ PredicateKind::Trait(..)
+ | PredicateKind::Projection(..)
+ | PredicateKind::Subtype(..)
+ | PredicateKind::Coerce(..)
+ | PredicateKind::RegionOutlives(..)
+ | PredicateKind::WellFormed(..)
+ | PredicateKind::ObjectSafe(..)
+ | PredicateKind::ClosureKind(..)
+ | PredicateKind::ConstEvaluatable(..)
+ | PredicateKind::ConstEquate(..)
+ | PredicateKind::TypeWellFormedFromEnv(..) => 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 an `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:
+/// ```ignore (illustrative)
+/// 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, TypeVisitable)]
+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()
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct OpaqueTypeKey<'tcx> {
+ pub def_id: LocalDefId,
+ pub substs: SubstsRef<'tcx>,
+}
+
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
+pub struct OpaqueHiddenType<'tcx> {
+ /// The span of this particular definition of the opaque type. So
+ /// for example:
+ ///
+ /// ```ignore (incomplete snippet)
+ /// type Foo = impl Baz;
+ /// fn bar() -> Foo {
+ /// // ^^^ This is the span we are looking for!
+ /// }
+ /// ```
+ ///
+ /// In cases where the fn returns `(impl Trait, impl Trait)` or
+ /// other such combinations, the result is currently
+ /// over-approximated, but better than nothing.
+ pub span: Span,
+
+ /// The type variable that represents the value of the opaque type
+ /// that we require. In other words, after we compile this function,
+ /// we will be created a constraint like:
+ /// ```ignore (pseudo-rust)
+ /// Foo<'a, T> = ?C
+ /// ```
+ /// where `?C` is the value of this type variable. =) It may
+ /// naturally refer to the type and lifetime parameters in scope
+ /// in this function, though ultimately it should only reference
+ /// those that are arguments to `Foo` in the constraint above. (In
+ /// other words, `?C` should not include `'b`, even though it's a
+ /// lifetime parameter on `foo`.)
+ pub ty: Ty<'tcx>,
+}
+
+impl<'tcx> OpaqueHiddenType<'tcx> {
+ pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) {
+ // Found different concrete types for the opaque type.
+ let mut err = tcx.sess.struct_span_err(
+ other.span,
+ "concrete type differs from previous defining opaque type use",
+ );
+ err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty));
+ if self.span == other.span {
+ err.span_label(
+ self.span,
+ "this expression supplies two conflicting concrete types for the same opaque type",
+ );
+ } else {
+ err.span_note(self.span, "previous use here");
+ }
+ err.emit();
+ }
+}
+
+/// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are
+/// identified by both a universe, as well as a name residing within that universe. Distinct bound
+/// regions/types/consts within the same universe simply have an unknown relationship to one
+/// another.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[derive(HashStable, TyEncodable, TyDecodable)]
+pub struct Placeholder<T> {
+ pub universe: UniverseIndex,
+ pub name: T,
+}
+
+pub type PlaceholderRegion = Placeholder<BoundRegionKind>;
+
+pub type PlaceholderType = Placeholder<BoundVar>;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(TyEncodable, TyDecodable, PartialOrd, Ord)]
+pub struct BoundConst<'tcx> {
+ pub var: BoundVar,
+ pub ty: Ty<'tcx>,
+}
+
+pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>;
+
+/// A `DefId` which, in case it is a const argument, is potentially bundled with
+/// the `DefId` of the generic parameter it instantiates.
+///
+/// This is used to avoid calls to `type_of` for const arguments during typeck
+/// which cause cycle errors.
+///
+/// ```rust
+/// struct A;
+/// impl A {
+/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
+/// // ^ const parameter
+/// }
+/// struct B;
+/// impl B {
+/// fn foo<const M: u8>(&self) -> usize { 42 }
+/// // ^ const parameter
+/// }
+///
+/// fn main() {
+/// let a = A;
+/// let _b = a.foo::<{ 3 + 7 }>();
+/// // ^^^^^^^^^ const argument
+/// }
+/// ```
+///
+/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know
+/// which `foo` is used until we know the type of `a`.
+///
+/// We only know the type of `a` once we are inside of `typeck(main)`.
+/// We also end up normalizing the type of `_b` during `typeck(main)` which
+/// requires us to evaluate the const argument.
+///
+/// To evaluate that const argument we need to know its type,
+/// which we would get using `type_of(const_arg)`. This requires us to
+/// resolve `foo` as it can be either `usize` or `u8` in this example.
+/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`,
+/// which results in a cycle.
+///
+/// In short we must not call `type_of(const_arg)` during `typeck(main)`.
+///
+/// When first creating the `ty::Const` of the const argument inside of `typeck` we have
+/// already resolved `foo` so we know which const parameter this argument instantiates.
+/// This means that we also know the expected result of `type_of(const_arg)` even if we
+/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is
+/// trivial to compute.
+///
+/// If we now want to use that constant in a place which potentially needs its type
+/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`,
+/// except that instead of a `Ty` we bundle the `DefId` of the const parameter.
+/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some`
+/// to get the type of `did`.
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, TyEncodable, TyDecodable)]
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Hash, HashStable)]
+pub struct WithOptConstParam<T> {
+ pub did: T,
+ /// The `DefId` of the corresponding generic parameter in case `did` is
+ /// a const argument.
+ ///
+ /// Note that even if `did` is a const argument, this may still be `None`.
+ /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)`
+ /// to potentially update `param_did` in the case it is `None`.
+ pub const_param_did: Option<DefId>,
+}
+
+impl<T> WithOptConstParam<T> {
+ /// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
+ #[inline(always)]
+ pub fn unknown(did: T) -> WithOptConstParam<T> {
+ WithOptConstParam { did, const_param_did: None }
+ }
+}
+
+impl WithOptConstParam<LocalDefId> {
+ /// Returns `Some((did, param_did))` if `def_id` is a const argument,
+ /// `None` otherwise.
+ #[inline(always)]
+ pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> {
+ tcx.opt_const_param_of(did).map(|param_did| (did, param_did))
+ }
+
+ /// In case `self` is unknown but `self.did` is a const argument, this returns
+ /// a `WithOptConstParam` with the correct `const_param_did`.
+ #[inline(always)]
+ pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> {
+ if self.const_param_did.is_none() {
+ if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) {
+ return Some(WithOptConstParam { did: self.did, const_param_did });
+ }
+ }
+
+ None
+ }
+
+ pub fn to_global(self) -> WithOptConstParam<DefId> {
+ WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
+ }
+
+ pub fn def_id_for_type_of(self) -> DefId {
+ if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() }
+ }
+}
+
+impl WithOptConstParam<DefId> {
+ pub fn as_local(self) -> Option<WithOptConstParam<LocalDefId>> {
+ self.did
+ .as_local()
+ .map(|did| WithOptConstParam { did, const_param_did: self.const_param_did })
+ }
+
+ pub fn as_const_arg(self) -> Option<(LocalDefId, DefId)> {
+ if let Some(param_did) = self.const_param_did {
+ if let Some(did) = self.did.as_local() {
+ return Some((did, param_did));
+ }
+ }
+
+ None
+ }
+
+ pub fn is_local(self) -> bool {
+ self.did.is_local()
+ }
+
+ pub fn def_id_for_type_of(self) -> DefId {
+ self.const_param_did.unwrap_or(self.did)
+ }
+}
+
+/// 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, Hash, PartialEq, Eq)]
+pub struct ParamEnv<'tcx> {
+ /// This packs both caller bounds and the reveal enum into one pointer.
+ ///
+ /// Caller bounds are `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.
+ ///
+ /// Use the `caller_bounds()` method to access.
+ ///
+ /// Typically, this is `Reveal::UserFacing`, but during codegen we
+ /// want `Reveal::All`.
+ ///
+ /// Note: This is packed, use the reveal() method to access it.
+ packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
+}
+
+#[derive(Copy, Clone)]
+struct ParamTag {
+ reveal: traits::Reveal,
+ constness: hir::Constness,
+}
+
+unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
+ const BITS: usize = 2;
+ #[inline]
+ fn into_usize(self) -> usize {
+ match self {
+ Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
+ Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
+ Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
+ Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
+ }
+ }
+ #[inline]
+ unsafe fn from_usize(ptr: usize) -> Self {
+ match ptr {
+ 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
+ 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
+ 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
+ 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
+ _ => std::hint::unreachable_unchecked(),
+ }
+ }
+}
+
+impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ParamEnv")
+ .field("caller_bounds", &self.caller_bounds())
+ .field("reveal", &self.reveal())
+ .field("constness", &self.constness())
+ .finish()
+ }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+ self.caller_bounds().hash_stable(hcx, hasher);
+ self.reveal().hash_stable(hcx, hasher);
+ self.constness().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
+ fn try_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ParamEnv::new(
+ self.caller_bounds().try_fold_with(folder)?,
+ self.reveal().try_fold_with(folder)?,
+ self.constness().try_fold_with(folder)?,
+ ))
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.caller_bounds().visit_with(visitor)?;
+ self.reveal().visit_with(visitor)?;
+ self.constness().visit_with(visitor)
+ }
+}
+
+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, hir::Constness::NotConst)
+ }
+
+ #[inline]
+ pub fn caller_bounds(self) -> &'tcx List<Predicate<'tcx>> {
+ self.packed.pointer()
+ }
+
+ #[inline]
+ pub fn reveal(self) -> traits::Reveal {
+ self.packed.tag().reveal
+ }
+
+ #[inline]
+ pub fn constness(self) -> hir::Constness {
+ self.packed.tag().constness
+ }
+
+ #[inline]
+ pub fn is_const(self) -> bool {
+ self.packed.tag().constness == hir::Constness::Const
+ }
+
+ /// 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, hir::Constness::NotConst)
+ }
+
+ /// Construct a trait environment with the given set of predicates.
+ #[inline]
+ pub fn new(
+ caller_bounds: &'tcx List<Predicate<'tcx>>,
+ reveal: Reveal,
+ constness: hir::Constness,
+ ) -> Self {
+ ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) }
+ }
+
+ pub fn with_user_facing(mut self) -> Self {
+ self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn with_constness(mut self, constness: hir::Constness) -> Self {
+ self.packed.set_tag(ParamTag { constness, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn with_const(mut self) -> Self {
+ self.packed.set_tag(ParamTag { constness: hir::Constness::Const, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.packed.set_tag(ParamTag { constness: hir::Constness::NotConst, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn remap_constness_with(&mut self, mut constness: ty::BoundConstness) {
+ *self = self.with_constness(constness.and(self.constness()))
+ }
+
+ /// 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.
+ /// All opaque types in the caller_bounds of the `ParamEnv`
+ /// will be normalized to their underlying types.
+ /// See PR #65989 and issue #65918 for more details
+ pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
+ if self.packed.tag().reveal == traits::Reveal::All {
+ return self;
+ }
+
+ ParamEnv::new(
+ tcx.normalize_opaque_types(self.caller_bounds()),
+ Reveal::All,
+ self.constness(),
+ )
+ }
+
+ /// Returns this same environment but with no caller bounds.
+ #[inline]
+ pub fn without_caller_bounds(self) -> Self {
+ Self::new(List::empty(), self.reveal(), self.constness())
+ }
+
+ /// 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: TypeVisitable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
+ match self.reveal() {
+ Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
+
+ Reveal::All => {
+ if value.is_global() {
+ ParamEnvAnd { param_env: self.without_caller_bounds(), value }
+ } else {
+ ParamEnvAnd { param_env: self, value }
+ }
+ }
+ }
+ }
+}
+
+// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
+// the constness of trait bounds is being propagated correctly.
+impl<'tcx> PolyTraitRef<'tcx> {
+ #[inline]
+ pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
+ self.map_bound(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ }
+
+ #[inline]
+ pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
+ self.with_constness(BoundConstness::NotConst)
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
+#[derive(HashStable)]
+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)
+ }
+
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.param_env = self.param_env.without_const();
+ self
+ }
+}
+
+#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
+pub struct Destructor {
+ /// The `DefId` of the destructor method
+ pub did: DefId,
+ /// The constness of the destructor method
+ pub constness: hir::Constness,
+}
+
+bitflags! {
+ #[derive(HashStable, TyEncodable, TyDecodable)]
+ 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;
+ /// Indicates whether this variant was obtained as part of recovering from
+ /// a syntactic error. May be incomplete or bogus.
+ const IS_RECOVERED = 1 << 1;
+ }
+}
+
+/// Definition of a variant -- a struct's fields or an enum variant.
+#[derive(Debug, HashStable, TyEncodable, TyDecodable)]
+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.
+ pub name: Symbol,
+ /// 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,
+}
+
+impl 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(
+ name: Symbol,
+ 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,
+ is_field_list_non_exhaustive: bool,
+ ) -> Self {
+ debug!(
+ "VariantDef::new(name = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
+ fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})",
+ name, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
+ );
+
+ let mut flags = VariantFlags::NO_VARIANT_FLAGS;
+ if is_field_list_non_exhaustive {
+ flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+ }
+
+ if recovered {
+ flags |= VariantFlags::IS_RECOVERED;
+ }
+
+ VariantDef {
+ def_id: variant_did.unwrap_or(parent_did),
+ ctor_def_id,
+ name,
+ discr,
+ fields,
+ ctor_kind,
+ flags,
+ }
+ }
+
+ /// 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)
+ }
+
+ /// Was this variant obtained as part of recovering from a syntactic error?
+ #[inline]
+ pub fn is_recovered(&self) -> bool {
+ self.flags.intersects(VariantFlags::IS_RECOVERED)
+ }
+
+ /// Computes the `Ident` of this variant by looking up the `Span`
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+ }
+}
+
+impl PartialEq for VariantDef {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ // There should be only one `VariantDef` for each `def_id`, therefore
+ // it is fine to implement `PartialEq` only based on `def_id`.
+ //
+ // Below, we exhaustively destructure `self` and `other` so that if the
+ // definition of `VariantDef` changes, a compile-error will be produced,
+ // reminding us to revisit this assumption.
+
+ let Self {
+ def_id: lhs_def_id,
+ ctor_def_id: _,
+ name: _,
+ discr: _,
+ fields: _,
+ ctor_kind: _,
+ flags: _,
+ } = &self;
+
+ let Self {
+ def_id: rhs_def_id,
+ ctor_def_id: _,
+ name: _,
+ discr: _,
+ fields: _,
+ ctor_kind: _,
+ flags: _,
+ } = other;
+
+ lhs_def_id == rhs_def_id
+ }
+}
+
+impl Eq for VariantDef {}
+
+impl Hash for VariantDef {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // There should be only one `VariantDef` for each `def_id`, therefore
+ // it is fine to implement `Hash` only based on `def_id`.
+ //
+ // Below, we exhaustively destructure `self` so that if the definition
+ // of `VariantDef` changes, a compile-error will be produced, reminding
+ // us to revisit this assumption.
+
+ let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } =
+ &self;
+
+ def_id.hash(s)
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, 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, TyEncodable, TyDecodable)]
+pub struct FieldDef {
+ pub did: DefId,
+ pub name: Symbol,
+ pub vis: Visibility,
+}
+
+impl PartialEq for FieldDef {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ // There should be only one `FieldDef` for each `did`, therefore it is
+ // fine to implement `PartialEq` only based on `did`.
+ //
+ // Below, we exhaustively destructure `self` so that if the definition
+ // of `FieldDef` changes, a compile-error will be produced, reminding
+ // us to revisit this assumption.
+
+ let Self { did: lhs_did, name: _, vis: _ } = &self;
+
+ let Self { did: rhs_did, name: _, vis: _ } = other;
+
+ lhs_did == rhs_did
+ }
+}
+
+impl Eq for FieldDef {}
+
+impl Hash for FieldDef {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // There should be only one `FieldDef` for each `did`, therefore it is
+ // fine to implement `Hash` only based on `did`.
+ //
+ // Below, we exhaustively destructure `self` so that if the definition
+ // of `FieldDef` changes, a compile-error will be produced, reminding
+ // us to revisit this assumption.
+
+ let Self { did, name: _, vis: _ } = &self;
+
+ did.hash(s)
+ }
+}
+
+bitflags! {
+ #[derive(TyEncodable, TyDecodable, 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, the type's layout can be randomized using
+ // the seed stored in `ReprOptions.layout_seed`
+ const RANDOMIZE_LAYOUT = 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, TyEncodable, TyDecodable, Default, HashStable)]
+pub struct ReprOptions {
+ pub int: Option<attr::IntType>,
+ pub align: Option<Align>,
+ pub pack: Option<Align>,
+ pub flags: ReprFlags,
+ /// The seed to be used for randomizing a type's layout
+ ///
+ /// Note: This could technically be a `[u8; 16]` (a `u128`) which would
+ /// be the "most accurate" hash as it'd encompass the item and crate
+ /// hash without loss, but it does pay the price of being larger.
+ /// Everything's a tradeoff, a `u64` seed should be sufficient for our
+ /// purposes (primarily `-Z randomize-layout`)
+ pub field_shuffle_seed: u64,
+}
+
+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;
+
+ // Generate a deterministically-derived seed from the item's path hash
+ // to allow for cross-crate compilation to actually work
+ let mut field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash();
+
+ // If the user defined a custom seed for layout randomization, xor the item's
+ // path hash with the user defined seed, this will allowing determinism while
+ // still allowing users to further randomize layout generation for e.g. fuzzing
+ if let Some(user_seed) = tcx.sess.opts.unstable_opts.layout_seed {
+ field_shuffle_seed ^= user_seed;
+ }
+
+ for attr in tcx.get_attrs(did, sym::repr) {
+ for r in attr::parse_repr_attr(&tcx.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::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()
+ }
+ });
+ }
+ }
+
+ // If `-Z randomize-layout` was enabled for the type definition then we can
+ // consider performing layout randomization
+ if tcx.sess.opts.unstable_opts.randomize_layout {
+ flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
+ }
+
+ // 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);
+ }
+
+ Self { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
+ }
+
+ #[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)
+ }
+
+ /// Returns the discriminant type, given these `repr` options.
+ /// This must only be called on enums!
+ 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 type is valid for reordering and `-Z randomize-layout`
+ /// was enabled for its declaration crate
+ pub fn can_randomize_type_layout(&self) -> bool {
+ !self.inhibit_struct_field_reordering_opt()
+ && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
+ }
+
+ /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
+ pub fn inhibit_union_abi_opt(&self) -> bool {
+ self.c()
+ }
+}
+
+impl<'tcx> FieldDef {
+ /// Returns the type of this field. The resulting type is not normalized. The `subst` is
+ /// typically obtained via the second field of [`TyKind::Adt`].
+ pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
+ tcx.bound_type_of(self.did).subst(tcx, subst)
+ }
+
+ /// Computes the `Ident` of this variant by looking up the `Span`
+ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+ Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
+ }
+}
+
+pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>;
+#[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:
+ ///
+ /// ```compile_fail,(E0119)
+ /// 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 typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> {
+ self.typeck(self.hir().body_owner_def_id(body))
+ }
+
+ pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
+ self.associated_items(id)
+ .in_definition_order()
+ .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
+ }
+
+ /// Look up the name of a definition across crates. This does not look at HIR.
+ pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
+ if let Some(cnum) = def_id.as_crate_root() {
+ Some(self.crate_name(cnum))
+ } else {
+ let def_key = self.def_key(def_id);
+ match def_key.disambiguated_data.data {
+ // The name of a constructor is that of its parent.
+ rustc_hir::definitions::DefPathData::Ctor => self
+ .opt_item_name(DefId { krate: def_id.krate, index: def_key.parent.unwrap() }),
+ // The name of opaque types only exists in HIR.
+ rustc_hir::definitions::DefPathData::ImplTrait
+ if let Some(def_id) = def_id.as_local() =>
+ self.hir().opt_name(self.hir().local_def_id_to_hir_id(def_id)),
+ _ => def_key.get_opt_name(),
+ }
+ }
+ }
+
+ /// Look up the name of a definition across crates. This does not look at HIR.
+ ///
+ /// This method will ICE if the corresponding item does not have a name. In these cases, use
+ /// [`opt_item_name`] instead.
+ ///
+ /// [`opt_item_name`]: Self::opt_item_name
+ pub fn item_name(self, id: DefId) -> Symbol {
+ self.opt_item_name(id).unwrap_or_else(|| {
+ bug!("item_name: no name for {:?}", self.def_path(id));
+ })
+ }
+
+ /// Look up the name and span of a definition.
+ ///
+ /// See [`item_name`][Self::item_name] for more information.
+ pub fn opt_item_ident(self, def_id: DefId) -> Option<Ident> {
+ let def = self.opt_item_name(def_id)?;
+ let span = def_id
+ .as_local()
+ .and_then(|id| self.def_ident_span(id))
+ .unwrap_or(rustc_span::DUMMY_SP);
+ Some(Ident::new(def, span))
+ }
+
+ pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
+ if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+ Some(self.associated_item(def_id))
+ } else {
+ None
+ }
+ }
+
+ pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>) -> usize {
+ typeck_results.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(self), 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);
+ self.adt_def(enum_did).variant_with_id(did)
+ }
+ Res::Def(DefKind::Struct | 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);
+ let enum_did = self.parent(variant_did);
+ 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);
+ self.adt_def(struct_did).non_enum_variant()
+ }
+ _ => bug!("expect_variant_res used with unexpected res {:?}", res),
+ }
+ }
+
+ /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
+ #[instrument(skip(self), level = "debug")]
+ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
+ match instance {
+ ty::InstanceDef::Item(def) => {
+ debug!("calling def_kind on def: {:?}", def);
+ let def_kind = self.def_kind(def.did);
+ debug!("returned from def_kind: {:?}", def_kind);
+ match def_kind {
+ DefKind::Const
+ | DefKind::Static(..)
+ | DefKind::AssocConst
+ | DefKind::Ctor(..)
+ | DefKind::AnonConst
+ | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
+ // If the caller wants `mir_for_ctfe` of a function they should not be using
+ // `instance_mir`, so we'll assume const fn also wants the optimized version.
+ _ => {
+ assert_eq!(def.const_param_did, None);
+ self.optimized_mir(def.did)
+ }
+ }
+ }
+ 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),
+ }
+ }
+
+ // FIXME(@lcnr): Remove this function.
+ pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] {
+ if let Some(did) = did.as_local() {
+ self.hir().attrs(self.hir().local_def_id_to_hir_id(did))
+ } else {
+ self.item_attrs(did)
+ }
+ }
+
+ /// Gets all attributes with the given name.
+ pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> {
+ let filter_fn = move |a: &&ast::Attribute| a.has_name(attr);
+ if let Some(did) = did.as_local() {
+ self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+ } else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) {
+ bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
+ } else {
+ self.item_attrs(did).iter().filter(filter_fn)
+ }
+ }
+
+ pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> {
+ self.get_attrs(did, attr).next()
+ }
+
+ /// Determines whether an item is annotated with an attribute.
+ pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
+ if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) {
+ bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
+ } else {
+ self.get_attrs(did, attr).next().is_some()
+ }
+ }
+
+ /// 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
+ }
+
+ /// Returns layout of a generator. Layout might be unavailable if the
+ /// generator is tainted by errors.
+ pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> {
+ self.optimized_mir(def_id).generator_layout()
+ }
+
+ /// 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 an item belonging to a trait,
+ /// returns the `DefId` of the trait that the trait item belongs to;
+ /// otherwise, returns `None`.
+ pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
+ if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+ let parent = self.parent(def_id);
+ if let DefKind::Trait | DefKind::TraitAlias = self.def_kind(parent) {
+ return Some(parent);
+ }
+ }
+ None
+ }
+
+ /// 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> {
+ if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+ let parent = self.parent(def_id);
+ if let DefKind::Impl = self.def_kind(parent) {
+ return Some(parent);
+ }
+ }
+ None
+ }
+
+ /// If the given `DefId` belongs to a trait that was automatically derived, returns `true`.
+ pub fn is_builtin_derive(self, def_id: DefId) -> bool {
+ self.has_attr(def_id, sym::automatically_derived)
+ }
+
+ /// 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 let Some(impl_did) = impl_did.as_local() {
+ Ok(self.def_span(impl_did))
+ } 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
+ // `normalize_to_macros_2_0()` 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.expn_that_defined(def_parent_def_id))
+ }
+
+ pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
+ ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope));
+ ident
+ }
+
+ pub fn adjust_ident_and_get_scope(
+ self,
+ mut ident: Ident,
+ scope: DefId,
+ block: hir::HirId,
+ ) -> (Ident, DefId) {
+ let scope = ident
+ .span
+ .normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope))
+ .and_then(|actual_expansion| actual_expansion.expn_data().parent_module)
+ .unwrap_or_else(|| self.parent_module(block).to_def_id());
+ (ident, scope)
+ }
+
+ pub fn is_object_safe(self, key: DefId) -> bool {
+ self.object_safety_violations(key).is_empty()
+ }
+
+ #[inline]
+ pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
+ matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
+ && self.constness(def_id) == hir::Constness::Const
+ }
+
+ #[inline]
+ pub fn is_const_default_method(self, def_id: DefId) -> bool {
+ matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
+ }
+}
+
+/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
+pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> {
+ let def_id = def_id.as_local()?;
+ if let Node::Item(item) = tcx.hir().get_by_def_id(def_id) {
+ if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
+ return match opaque_ty.origin {
+ hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
+ Some(parent)
+ }
+ hir::OpaqueTyOrigin::TyAlias => None,
+ };
+ }
+ }
+ None
+}
+
+pub fn int_ty(ity: ast::IntTy) -> IntTy {
+ match ity {
+ ast::IntTy::Isize => IntTy::Isize,
+ ast::IntTy::I8 => IntTy::I8,
+ ast::IntTy::I16 => IntTy::I16,
+ ast::IntTy::I32 => IntTy::I32,
+ ast::IntTy::I64 => IntTy::I64,
+ ast::IntTy::I128 => IntTy::I128,
+ }
+}
+
+pub fn uint_ty(uty: ast::UintTy) -> UintTy {
+ match uty {
+ ast::UintTy::Usize => UintTy::Usize,
+ ast::UintTy::U8 => UintTy::U8,
+ ast::UintTy::U16 => UintTy::U16,
+ ast::UintTy::U32 => UintTy::U32,
+ ast::UintTy::U64 => UintTy::U64,
+ ast::UintTy::U128 => UintTy::U128,
+ }
+}
+
+pub fn float_ty(fty: ast::FloatTy) -> FloatTy {
+ match fty {
+ ast::FloatTy::F32 => FloatTy::F32,
+ ast::FloatTy::F64 => FloatTy::F64,
+ }
+}
+
+pub fn ast_int_ty(ity: IntTy) -> ast::IntTy {
+ match ity {
+ IntTy::Isize => ast::IntTy::Isize,
+ IntTy::I8 => ast::IntTy::I8,
+ IntTy::I16 => ast::IntTy::I16,
+ IntTy::I32 => ast::IntTy::I32,
+ IntTy::I64 => ast::IntTy::I64,
+ IntTy::I128 => ast::IntTy::I128,
+ }
+}
+
+pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy {
+ match uty {
+ UintTy::Usize => ast::UintTy::Usize,
+ UintTy::U8 => ast::UintTy::U8,
+ UintTy::U16 => ast::UintTy::U16,
+ UintTy::U32 => ast::UintTy::U32,
+ UintTy::U64 => ast::UintTy::U64,
+ UintTy::U128 => ast::UintTy::U128,
+ }
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ closure::provide(providers);
+ context::provide(providers);
+ erase_regions::provide(providers);
+ layout::provide(providers);
+ util::provide(providers);
+ print::provide(providers);
+ super::util::bug::provide(providers);
+ super::middle::provide(providers);
+ *providers = ty::query::Providers {
+ trait_impls_of: trait_def::trait_impls_of_provider,
+ incoherent_impls: trait_def::incoherent_impls_provider,
+ type_uninhabited_from: inhabitedness::type_uninhabited_from,
+ const_param_default: consts::const_param_default,
+ vtable_allocation: vtable::vtable_allocation_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: LocalDefIdMap<Vec<DefId>>,
+ pub incoherent_impls: FxHashMap<SimplifiedType, Vec<LocalDefId>>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
+pub struct SymbolName<'tcx> {
+ /// `&str` gives a consistent ordering, which ensures reproducible builds.
+ pub name: &'tcx str,
+}
+
+impl<'tcx> SymbolName<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>, name: &str) -> SymbolName<'tcx> {
+ SymbolName {
+ name: unsafe { str::from_utf8_unchecked(tcx.arena.alloc_slice(name.as_bytes())) },
+ }
+ }
+}
+
+impl<'tcx> fmt::Display for SymbolName<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.name, fmt)
+ }
+}
+
+impl<'tcx> fmt::Debug for SymbolName<'tcx> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.name, fmt)
+ }
+}
+
+#[derive(Debug, Default, Copy, Clone)]
+pub struct FoundRelationships {
+ /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
+ /// obligation, where:
+ ///
+ /// * `Foo` is not `Sized`
+ /// * `(): Foo` may be satisfied
+ pub self_in_trait: bool,
+ /// This is true if we identified that this Ty (`?T`) is found in a `<_ as
+ /// _>::AssocType = ?T`
+ pub output: bool,
+}
+
+/// The constituent parts of a type level constant of kind ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredConst<'tcx> {
+ pub variant: Option<VariantIdx>,
+ pub fields: &'tcx [ty::Const<'tcx>],
+}
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
new file mode 100644
index 000000000..9d8a81165
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -0,0 +1,283 @@
+//! 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_generic_arg_after_erasing_regions` query for each type
+//! or constant found within. (This underlying query is what is cached.)
+
+use crate::mir;
+use crate::traits::query::NoSolution;
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
+use crate::ty::subst::{Subst, SubstsRef};
+use crate::ty::{self, EarlyBinder, Ty, TyCtxt};
+
+#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
+pub enum NormalizationError<'tcx> {
+ Type(Ty<'tcx>),
+ Const(ty::Const<'tcx>),
+ ConstantKind(mir::ConstantKind<'tcx>),
+}
+
+impl<'tcx> NormalizationError<'tcx> {
+ pub fn get_type_for_failure(&self) -> String {
+ match self {
+ NormalizationError::Type(t) => format!("{}", t),
+ NormalizationError::Const(c) => format!("{}", c),
+ NormalizationError::ConstantKind(ck) => format!("{}", ck),
+ }
+ }
+}
+
+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 should only be used outside of type inference. For example,
+ /// it assumes that normalization will succeed.
+ 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);
+ debug!(?value);
+
+ if !value.has_projections() {
+ value
+ } else {
+ value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+ }
+ }
+
+ /// Tries to erase the regions in `value` and then fully normalize all the
+ /// types found within. The result will also have regions erased.
+ ///
+ /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
+ /// succeeds.
+ pub fn try_normalize_erasing_regions<T>(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "try_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);
+ debug!(?value);
+
+ if !value.has_projections() {
+ Ok(value)
+ } else {
+ let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
+ value.try_fold_with(&mut folder)
+ }
+ }
+
+ /// If you have a `Binder<'tcx, 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<'tcx, T>,
+ ) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ let value = self.erase_late_bound_regions(value);
+ self.normalize_erasing_regions(param_env, value)
+ }
+
+ /// If you have a `Binder<'tcx, 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 try_normalize_erasing_late_bound_regions<T>(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ value: ty::Binder<'tcx, T>,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ let value = self.erase_late_bound_regions(value);
+ self.try_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.
+ /// Panics if normalization fails. In case normalization might fail
+ /// use `try_subst_and_normalize_erasing_regions` instead.
+ 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 = EarlyBinder(value).subst(self, param_substs);
+ self.normalize_erasing_regions(param_env, substituted)
+ }
+
+ /// Monomorphizes a type from the AST by first applying the
+ /// in-scope substitutions and then trying to normalize any associated
+ /// types. Contrary to `subst_and_normalize_erasing_regions` this does
+ /// not assume that normalization succeeds.
+ pub fn try_subst_and_normalize_erasing_regions<T>(
+ self,
+ param_substs: SubstsRef<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "subst_and_normalize_erasing_regions(\
+ param_substs={:?}, \
+ value={:?}, \
+ param_env={:?})",
+ param_substs, value, param_env,
+ );
+ let substituted = EarlyBinder(value).subst(self, param_substs);
+ self.try_normalize_erasing_regions(param_env, substituted)
+ }
+}
+
+struct NormalizeAfterErasingRegionsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
+ #[instrument(skip(self), level = "debug")]
+ fn normalize_generic_arg_after_erasing_regions(
+ &self,
+ arg: ty::GenericArg<'tcx>,
+ ) -> ty::GenericArg<'tcx> {
+ let arg = self.param_env.and(arg);
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
+ "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
+ arg.value
+ ))
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
+ }
+
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
+ }
+
+ #[inline]
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ self.tcx
+ .try_normalize_mir_const_after_erasing_regions(arg)
+ .unwrap_or_else(|_| bug!("failed to normalize {:?}", c))
+ }
+}
+
+struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn try_normalize_generic_arg_after_erasing_regions(
+ &self,
+ arg: ty::GenericArg<'tcx>,
+ ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
+ let arg = self.param_env.and(arg);
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
+ }
+}
+
+impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ type Error = NormalizationError<'tcx>;
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
+ Ok(t) => Ok(t.expect_ty()),
+ Err(_) => Err(NormalizationError::Type(ty)),
+ }
+ }
+
+ fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
+ Ok(t) => Ok(t.expect_const()),
+ Err(_) => Err(NormalizationError::Const(c)),
+ }
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
+ Ok(c) => Ok(c),
+ Err(_) => Err(NormalizationError::ConstantKind(c)),
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
new file mode 100644
index 000000000..e189ee2fc
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -0,0 +1,119 @@
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::{Idx, IndexVec};
+
+use crate::middle::exported_symbols::ExportedSymbol;
+use crate::mir::Body;
+use crate::ty::abstract_const::Node;
+use crate::ty::{
+ self, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty,
+};
+
+pub trait ParameterizedOverTcx: 'static {
+ #[allow(unused_lifetimes)]
+ type Value<'tcx>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for &'static [T] {
+ type Value<'tcx> = &'tcx [T::Value<'tcx>];
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> {
+ type Value<'tcx> = Option<T::Value<'tcx>>;
+}
+
+impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) {
+ type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>);
+}
+
+impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> {
+ type Value<'tcx> = IndexVec<I, T::Value<'tcx>>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
+ type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
+}
+
+#[macro_export]
+macro_rules! trivially_parameterized_over_tcx {
+ ($($ty:ty),+ $(,)?) => {
+ $(
+ impl $crate::ty::ParameterizedOverTcx for $ty {
+ #[allow(unused_lifetimes)]
+ type Value<'tcx> = $ty;
+ }
+ )*
+ }
+}
+
+trivially_parameterized_over_tcx! {
+ usize,
+ (),
+ u32,
+ std::string::String,
+ crate::metadata::ModChild,
+ crate::middle::codegen_fn_attrs::CodegenFnAttrs,
+ crate::middle::exported_symbols::SymbolExportInfo,
+ crate::mir::ConstQualifs,
+ ty::Generics,
+ ty::ImplPolarity,
+ ty::ReprOptions,
+ ty::TraitDef,
+ ty::Visibility,
+ ty::adjustment::CoerceUnsizedInfo,
+ ty::fast_reject::SimplifiedTypeGen<DefId>,
+ rustc_ast::Attribute,
+ rustc_ast::MacArgs,
+ rustc_attr::ConstStability,
+ rustc_attr::Deprecation,
+ rustc_attr::Stability,
+ rustc_hir::Constness,
+ rustc_hir::Defaultness,
+ rustc_hir::GeneratorKind,
+ rustc_hir::IsAsync,
+ rustc_hir::LangItem,
+ rustc_hir::def::DefKind,
+ rustc_hir::def_id::DefIndex,
+ rustc_hir::definitions::DefKey,
+ rustc_index::bit_set::FiniteBitSet<u32>,
+ rustc_session::cstore::ForeignModule,
+ rustc_session::cstore::LinkagePreference,
+ rustc_session::cstore::NativeLib,
+ rustc_span::DebuggerVisualizerFile,
+ rustc_span::ExpnData,
+ rustc_span::ExpnHash,
+ rustc_span::ExpnId,
+ rustc_span::SourceFile,
+ rustc_span::Span,
+ rustc_span::Symbol,
+ rustc_span::def_id::DefPathHash,
+ rustc_span::hygiene::SyntaxContextData,
+ rustc_span::symbol::Ident,
+ rustc_type_ir::Variance,
+}
+
+// HACK(compiler-errors): This macro rule can only take an ident,
+// not a path, due to parsing ambiguity reasons. That means we gotta
+// import all of these types above.
+#[macro_export]
+macro_rules! parameterized_over_tcx {
+ ($($ident:ident),+ $(,)?) => {
+ $(
+ impl $crate::ty::ParameterizedOverTcx for $ident<'static> {
+ type Value<'tcx> = $ident<'tcx>;
+ }
+ )*
+ }
+}
+
+parameterized_over_tcx! {
+ Ty,
+ FnSig,
+ GenericPredicates,
+ TraitRef,
+ Const,
+ Predicate,
+ GeneratorDiagnosticData,
+ Body,
+ Node,
+ ExportedSymbol,
+}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
new file mode 100644
index 000000000..d57cf8f01
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -0,0 +1,327 @@
+use crate::ty::subst::{GenericArg, Subst};
+use crate::ty::{self, DefIdTree, Ty, TyCtxt};
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+
+// `pretty` is a separate module only for organization.
+mod pretty;
+pub use self::pretty::*;
+
+// 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>(&'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<'tcx>) -> 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::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ ) -> Result<Self::DynExistential, Self::Error>;
+
+ fn print_const(self, ct: 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 overridden):
+
+ #[instrument(skip(self), level = "debug")]
+ fn default_print_def_path(
+ self,
+ def_id: DefId,
+ substs: &'tcx [GenericArg<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ let key = self.tcx().def_key(def_id);
+ debug!(?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 self_ty = self.tcx().bound_type_of(def_id);
+ let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
+ let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
+ (
+ self_ty.subst(self.tcx(), substs),
+ impl_trait_ref.map(|i| i.subst(self.tcx(), substs)),
+ )
+ } else {
+ (self_ty.0, impl_trait_ref.map(|i| i.0))
+ };
+ 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 => {}
+ // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`.
+ // Anon consts doesn't have their own generics, and inline consts' own
+ // generics are their inferred types, so don't print them.
+ DefPathData::AnonConst => {}
+
+ // 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 = generics.own_substs_no_defaults(self.tcx(), 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 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) == parent_def_id,
+ };
+ let in_trait_mod = match impl_trait_ref {
+ None => false,
+ Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == 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.
+///
+/// Visited set is needed to avoid full iteration over
+/// deeply nested tuples that have no DefId.
+fn characteristic_def_id_of_type_cached<'a>(
+ ty: Ty<'a>,
+ visited: &mut SsoHashSet<Ty<'a>>,
+) -> 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_cached(subty, visited)
+ }
+
+ ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited),
+
+ ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
+
+ ty::Tuple(ref tys) => tys.iter().find_map(|ty| {
+ if visited.insert(ty) {
+ return characteristic_def_id_of_type_cached(ty, visited);
+ }
+ return None;
+ }),
+
+ 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::Param(_)
+ | ty::Opaque(..)
+ | ty::Infer(_)
+ | ty::Bound(..)
+ | ty::Error(_)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ | ty::Float(_) => None,
+ }
+}
+pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
+ characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
+}
+
+impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> {
+ 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::Binder<'tcx, 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 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/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
new file mode 100644
index 000000000..7f2e81a71
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -0,0 +1,2789 @@
+use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
+use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
+use crate::ty::{
+ self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
+ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
+};
+use rustc_apfloat::ieee::{Double, Single};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir as hir;
+use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
+use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
+use rustc_session::config::TrimmedDefPaths;
+use rustc_session::cstore::{ExternCrate, ExternCrateSource};
+use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
+
+use std::cell::Cell;
+use std::char;
+use std::collections::BTreeMap;
+use std::convert::TryFrom;
+use std::fmt::{self, Write as _};
+use std::iter;
+use std::ops::{ControlFlow, Deref, DerefMut};
+
+// `pretty` is a separate module only for organization.
+use super::*;
+
+macro_rules! p {
+ (@$lit:literal) => {
+ write!(scoped_cx!(), $lit)?
+ };
+ (@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),*)?
+ };
+ ($($elem:tt $(($($args:tt)*))?),+) => {{
+ $(p!(@ $elem $(($($args)*))?);)+
+ }};
+}
+macro_rules! define_scoped_cx {
+ ($cx:ident) => {
+ #[allow(unused_macros)]
+ macro_rules! scoped_cx {
+ () => {
+ $cx
+ };
+ }
+ };
+}
+
+thread_local! {
+ static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
+ static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
+ static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
+ static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
+ static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
+}
+
+macro_rules! define_helper {
+ ($($(#[$a:meta])* fn $name:ident($helper:ident, $tl:ident);)+) => {
+ $(
+ #[must_use]
+ pub struct $helper(bool);
+
+ impl $helper {
+ pub fn new() -> $helper {
+ $helper($tl.with(|c| c.replace(true)))
+ }
+ }
+
+ $(#[$a])*
+ pub macro $name($e:expr) {
+ {
+ let _guard = $helper::new();
+ $e
+ }
+ }
+
+ impl Drop for $helper {
+ fn drop(&mut self) {
+ $tl.with(|c| c.set(self.0))
+ }
+ }
+ )+
+ }
+}
+
+define_helper!(
+ /// 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. `explicit_item_bounds`
+ /// for opaque types), to ensure that any debug printing that
+ /// occurs during the query computation does not end up recursively
+ /// calling the same query.
+ fn with_no_queries(NoQueriesGuard, NO_QUERIES);
+ /// 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.
+ fn with_forced_impl_filename_line(ForcedImplGuard, FORCE_IMPL_FILENAME_LINE);
+ /// Adds the `crate::` prefix to paths where appropriate.
+ fn with_crate_prefix(CratePrefixGuard, SHOULD_PREFIX_WITH_CRATE);
+ /// Prevent path trimming if it is turned on. Path trimming affects `Display` impl
+ /// of various rustc types, for example `std::vec::Vec` would be trimmed to `Vec`,
+ /// if no other `Vec` is found.
+ fn with_no_trimmed_paths(NoTrimmedGuard, NO_TRIMMED_PATH);
+ /// Prevent selection of visible paths. `Display` impl of DefId will prefer
+ /// visible (public) reexports of types as paths.
+ fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
+);
+
+/// 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)]
+pub struct RegionHighlightMode<'tcx> {
+ tcx: TyCtxt<'tcx>,
+
+ /// If enabled, when we see the selected region, use "`'N`"
+ /// instead of the ordinary behavior.
+ highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
+
+ /// If enabled, when printing a "free region" that originated from
+ /// the given `ty::BoundRegionKind`, 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::BoundRegionKind, usize)>,
+}
+
+impl<'tcx> RegionHighlightMode<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+ Self {
+ tcx,
+ highlight_regions: Default::default(),
+ highlight_bound_region: Default::default(),
+ }
+ }
+
+ /// If `region` and `number` are both `Some`, invokes
+ /// `highlighting_region`.
+ pub fn maybe_highlighting_region(
+ &mut self,
+ region: Option<ty::Region<'tcx>>,
+ 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<'tcx>, number: usize) {
+ let num_slots = self.highlight_regions.len();
+ let first_avail_slot =
+ self.highlight_regions.iter_mut().find(|s| s.is_none()).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(self.tcx.mk_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<'tcx>) -> Option<usize> {
+ self.highlight_regions.iter().find_map(|h| match h {
+ Some((r, n)) if *r == region => Some(*n),
+ _ => None,
+ })
+ }
+
+ /// 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::BoundRegionKind, 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<'tcx, T>) -> Result<Self, Self::Error>
+ where
+ T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
+ {
+ value.as_ref().skip_binder().print(self)
+ }
+
+ fn wrap_binder<T, F: FnOnce(&T, Self) -> Result<Self, fmt::Error>>(
+ self,
+ value: &ty::Binder<'tcx, T>,
+ f: F,
+ ) -> Result<Self, Self::Error>
+ where
+ T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
+ {
+ f(value.as_ref().skip_binder(), 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 `{f: t}` or `{f as t}` depending on the `cast` argument
+ fn typed_value(
+ mut self,
+ f: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ t: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ conversion: &str,
+ ) -> Result<Self::Const, Self::Error> {
+ self.write_str("{")?;
+ self = f(self)?;
+ self.write_str(conversion)?;
+ self = t(self)?;
+ self.write_str("}")?;
+ 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 should_print_region(&self, region: ty::Region<'tcx>) -> bool;
+
+ // Defaults (should not be overridden):
+
+ /// 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> {
+ if NO_VISIBLE_PATH.with(|flag| flag.get()) {
+ return Ok((self, false));
+ }
+
+ let mut callers = Vec::new();
+ self.try_print_visible_def_path_recur(def_id, &mut callers)
+ }
+
+ /// Try to see if this path can be trimmed to a unique symbol name.
+ fn try_print_trimmed_def_path(
+ mut self,
+ def_id: DefId,
+ ) -> Result<(Self::Path, bool), Self::Error> {
+ if !self.tcx().sess.opts.unstable_opts.trim_diagnostic_paths
+ || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never)
+ || NO_TRIMMED_PATH.with(|flag| flag.get())
+ || SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get())
+ {
+ return Ok((self, false));
+ }
+
+ match self.tcx().trimmed_def_paths(()).get(&def_id) {
+ None => Ok((self, false)),
+ Some(symbol) => {
+ self.write_str(symbol.as_str())?;
+ Ok((self, true))
+ }
+ }
+ }
+
+ /// 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 called 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.
+ ///
+ /// This method returns false if we can't print the visible path, so
+ /// `print_def_path` can fall back on the item's real definition path.
+ 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 let Some(cnum) = def_id.as_crate_root() {
+ 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, dependency_of, span, .. }) => match (src, dependency_of) {
+ (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
+ // NOTE(eddyb) the only reason `span` might be dummy,
+ // that we're aware of, is that it's the `std`/`core`
+ // `extern crate` injected by default.
+ // FIXME(eddyb) find something better to key this on,
+ // or avoid ending up with `ExternCrateSource::Extern`,
+ // for the injected `std`/`core`.
+ if span.is_dummy() {
+ return Ok((self.path_crate(cnum)?, true));
+ }
+
+ // Disable `try_print_trimmed_def_path` behavior within
+ // the `print_def_path` call, to avoid infinite recursion
+ // in cases where the `extern crate foo` has non-trivial
+ // parents, e.g. it's nested in `impl foo::Trait for Bar`
+ // (see also issues #55779 and #87932).
+ self = with_no_visible_paths!(self.print_def_path(def_id, &[])?);
+
+ return Ok((self, true));
+ }
+ (ExternCrateSource::Path, LOCAL_CRATE) => {
+ return Ok((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(());
+
+ 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>.
+ if let DefPathData::Ctor = cur_def_key.disambiguated_data.data {
+ 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 Some(visible_parent) = visible_parent_map.get(&def_id).cloned() else {
+ return Ok((self, false));
+ };
+
+ let actual_parent = self.tcx().opt_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` reexports 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 => {
+ // Item might be re-exported several times, but filter for the one
+ // that's public and whose identifier isn't `_`.
+ let reexport = self
+ .tcx()
+ .module_children(visible_parent)
+ .iter()
+ .filter(|child| child.res.opt_def_id() == Some(def_id))
+ .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
+ .map(|child| child.ident.name);
+
+ if let Some(new_name) = reexport {
+ *name = new_name;
+ } else {
+ // There is no name that is public and isn't `_`, so bail.
+ return Ok((self, false));
+ }
+ }
+ // Re-exported `extern crate` (#43189).
+ DefPathData::CrateRoot => {
+ data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
+ }
+ _ => {}
+ }
+ debug!("try_print_visible_def_path: data={:?}", data);
+
+ 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();
+
+ 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!(" 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!("impl ");
+ if let Some(trait_ref) = trait_ref {
+ p!(print(trait_ref.print_only_trait_path()), " 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!("bool"),
+ ty::Char => p!("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!("&");
+ if self.should_print_region(r) {
+ p!(print(r), " ");
+ }
+ p!(print(ty::TypeAndMut { ty, mutbl }))
+ }
+ ty::Never => p!("!"),
+ ty::Tuple(ref tys) => {
+ p!("(", comma_sep(tys.iter()));
+ if tys.len() == 1 {
+ p!(",");
+ }
+ p!(")")
+ }
+ ty::FnDef(def_id, substs) => {
+ let sig = self.tcx().bound_fn_sig(def_id).subst(self.tcx(), substs);
+ p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
+ }
+ ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
+ ty::Infer(infer_ty) => {
+ let verbose = self.tcx().sess.verbose();
+ if let ty::TyVar(ty_vid) = infer_ty {
+ if let Some(name) = self.ty_infer_name(ty_vid) {
+ p!(write("{}", name))
+ } else {
+ if verbose {
+ p!(write("{:?}", infer_ty))
+ } else {
+ p!(write("{}", infer_ty))
+ }
+ }
+ } else {
+ if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
+ }
+ }
+ ty::Error(_) => p!("[type error]"),
+ ty::Param(ref param_ty) => p!(print(param_ty)),
+ ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
+ ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
+ 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.should_print_region(r);
+ if print_r {
+ p!("(");
+ }
+ p!("dyn ", print(data));
+ if print_r {
+ p!(" + ", print(r), ")");
+ }
+ }
+ ty::Foreign(def_id) => {
+ p!(print_def_path(def_id, &[]));
+ }
+ ty::Projection(ref data) => p!(print(data)),
+ 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_middle::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);
+ }
+
+ let parent = self.tcx().parent(def_id);
+ match self.tcx().def_kind(parent) {
+ DefKind::TyAlias | DefKind::AssocTy => {
+ if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
+ if d == def_id {
+ // If the type alias directly starts with the `impl` of the
+ // opaque type we're printing, then skip the `::{opaque#1}`.
+ p!(print_def_path(parent, substs));
+ return Ok(self);
+ }
+ }
+ // Complex opaque type, e.g. `type Foo = (i32, impl Debug);`
+ p!(print_def_path(def_id, substs));
+ return Ok(self);
+ }
+ _ => return self.pretty_print_opaque_impl_type(def_id, substs),
+ }
+ }
+ ty::Str => p!("str"),
+ ty::Generator(did, substs, movability) => {
+ p!(write("["));
+ match movability {
+ hir::Movability::Movable => {}
+ hir::Movability::Static => p!("static "),
+ }
+
+ if !self.tcx().sess.verbose() {
+ p!("generator");
+ // FIXME(eddyb) should use `def_span`.
+ if let Some(did) = did.as_local() {
+ let span = self.tcx().def_span(did);
+ p!(write(
+ "@{}",
+ // This may end up in stderr diagnostics but it may also be emitted
+ // into MIR. Hence we use the remapped path if available
+ self.tcx().sess.source_map().span_to_embeddable_string(span)
+ ));
+ } else {
+ p!(write("@"), print_def_path(did, substs));
+ }
+ } else {
+ p!(print_def_path(did, substs));
+ p!(" upvar_tys=(");
+ if !substs.as_generator().is_valid() {
+ p!("unavailable");
+ } else {
+ self = self.comma_sep(substs.as_generator().upvar_tys())?;
+ }
+ p!(")");
+
+ if substs.as_generator().is_valid() {
+ p!(" ", print(substs.as_generator().witness()));
+ }
+ }
+
+ p!("]")
+ }
+ ty::GeneratorWitness(types) => {
+ p!(in_binder(&types));
+ }
+ ty::Closure(did, substs) => {
+ p!(write("["));
+ if !self.tcx().sess.verbose() {
+ p!(write("closure"));
+ // FIXME(eddyb) should use `def_span`.
+ if let Some(did) = did.as_local() {
+ if self.tcx().sess.opts.unstable_opts.span_free_formats {
+ p!("@", print_def_path(did.to_def_id(), substs));
+ } else {
+ let span = self.tcx().def_span(did);
+ p!(write(
+ "@{}",
+ // This may end up in stderr diagnostics but it may also be emitted
+ // into MIR. Hence we use the remapped path if available
+ self.tcx().sess.source_map().span_to_embeddable_string(span)
+ ));
+ }
+ } else {
+ p!(write("@"), print_def_path(did, substs));
+ }
+ } else {
+ p!(print_def_path(did, substs));
+ if !substs.as_closure().is_valid() {
+ p!(" closure_substs=(unavailable)");
+ p!(write(" substs={:?}", substs));
+ } else {
+ p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
+ p!(
+ " closure_sig_as_fn_ptr_ty=",
+ print(substs.as_closure().sig_as_fn_ptr_ty())
+ );
+ p!(" upvar_tys=(");
+ self = self.comma_sep(substs.as_closure().upvar_tys())?;
+ p!(")");
+ }
+ }
+ p!("]");
+ }
+ ty::Array(ty, sz) => {
+ p!("[", print(ty), "; ");
+ if self.tcx().sess.verbose() {
+ p!(write("{:?}", sz));
+ } else if let ty::ConstKind::Unevaluated(..) = sz.kind() {
+ // Do not try to evaluate 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!("_");
+ } else if let Some(n) = sz.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
+ p!(write("{}", n));
+ } else if let ty::ConstKind::Param(param) = sz.kind() {
+ p!(print(param));
+ } else {
+ p!("_");
+ }
+ p!("]")
+ }
+ ty::Slice(ty) => p!("[", print(ty), "]"),
+ }
+
+ Ok(self)
+ }
+
+ fn pretty_print_opaque_impl_type(
+ mut self,
+ def_id: DefId,
+ substs: &'tcx ty::List<ty::GenericArg<'tcx>>,
+ ) -> Result<Self::Type, Self::Error> {
+ let tcx = self.tcx();
+
+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+ // by looking up the projections associated with the def_id.
+ let bounds = tcx.bound_explicit_item_bounds(def_id);
+
+ let mut traits = FxIndexMap::default();
+ let mut fn_traits = FxIndexMap::default();
+ let mut is_sized = false;
+
+ for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
+ let predicate = predicate.subst(tcx, substs);
+ let bound_predicate = predicate.kind();
+
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ let trait_ref = bound_predicate.rebind(pred.trait_ref);
+
+ // Don't print + Sized, but rather + ?Sized if absent.
+ if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
+ is_sized = true;
+ continue;
+ }
+
+ self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
+ }
+ ty::PredicateKind::Projection(pred) => {
+ let proj_ref = bound_predicate.rebind(pred);
+ let trait_ref = proj_ref.required_poly_trait_ref(tcx);
+
+ // Projection type entry -- the def-id for naming, and the ty.
+ let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
+
+ self.insert_trait_and_projection(
+ trait_ref,
+ Some(proj_ty),
+ &mut traits,
+ &mut fn_traits,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ write!(self, "impl ")?;
+
+ let mut first = true;
+ // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
+ let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
+
+ for (fn_once_trait_ref, entry) in fn_traits {
+ write!(self, "{}", if first { "" } else { " + " })?;
+ write!(self, "{}", if paren_needed { "(" } else { "" })?;
+
+ self = self.wrap_binder(&fn_once_trait_ref, |trait_ref, mut cx| {
+ define_scoped_cx!(cx);
+ // Get the (single) generic ty (the args) of this FnOnce trait ref.
+ let generics = tcx.generics_of(trait_ref.def_id);
+ let args = generics.own_substs_no_defaults(tcx, trait_ref.substs);
+
+ match (entry.return_ty, args[0].expect_ty()) {
+ // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
+ // a return type.
+ (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
+ let name = if entry.fn_trait_ref.is_some() {
+ "Fn"
+ } else if entry.fn_mut_trait_ref.is_some() {
+ "FnMut"
+ } else {
+ "FnOnce"
+ };
+
+ p!(write("{}(", name));
+
+ for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
+ if idx > 0 {
+ p!(", ");
+ }
+ p!(print(ty));
+ }
+
+ p!(")");
+ if let Term::Ty(ty) = return_ty.skip_binder() {
+ if !ty.is_unit() {
+ p!(" -> ", print(return_ty));
+ }
+ }
+ p!(write("{}", if paren_needed { ")" } else { "" }));
+
+ first = false;
+ }
+ // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
+ // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
+ _ => {
+ if entry.has_fn_once {
+ traits.entry(fn_once_trait_ref).or_default().extend(
+ // Group the return ty with its def id, if we had one.
+ entry
+ .return_ty
+ .map(|ty| (tcx.lang_items().fn_once_output().unwrap(), ty)),
+ );
+ }
+ if let Some(trait_ref) = entry.fn_mut_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ if let Some(trait_ref) = entry.fn_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ }
+ }
+
+ Ok(cx)
+ })?;
+ }
+
+ // Print the rest of the trait types (that aren't Fn* family of traits)
+ for (trait_ref, assoc_items) in traits {
+ write!(self, "{}", if first { "" } else { " + " })?;
+
+ self = self.wrap_binder(&trait_ref, |trait_ref, mut cx| {
+ define_scoped_cx!(cx);
+ p!(print(trait_ref.print_only_trait_name()));
+
+ let generics = tcx.generics_of(trait_ref.def_id);
+ let args = generics.own_substs_no_defaults(tcx, trait_ref.substs);
+
+ if !args.is_empty() || !assoc_items.is_empty() {
+ let mut first = true;
+
+ for ty in args {
+ if first {
+ p!("<");
+ first = false;
+ } else {
+ p!(", ");
+ }
+ p!(print(ty));
+ }
+
+ for (assoc_item_def_id, term) in assoc_items {
+ // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
+ // unless we can find out what generator return type it comes from.
+ let term = if let Some(ty) = term.skip_binder().ty()
+ && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind()
+ && Some(*item_def_id) == tcx.lang_items().generator_return()
+ {
+ if let ty::Generator(_, substs, _) = substs.type_at(0).kind() {
+ let return_ty = substs.as_generator().return_ty();
+ if !return_ty.is_ty_infer() {
+ return_ty.into()
+ } else {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ } else {
+ term.skip_binder()
+ };
+
+ if first {
+ p!("<");
+ first = false;
+ } else {
+ p!(", ");
+ }
+
+ p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
+
+ match term {
+ Term::Ty(ty) => {
+ p!(print(ty))
+ }
+ Term::Const(c) => {
+ p!(print(c));
+ }
+ };
+ }
+
+ if !first {
+ p!(">");
+ }
+ }
+
+ first = false;
+ Ok(cx)
+ })?;
+ }
+
+ if !is_sized {
+ write!(self, "{}?Sized", if first { "" } else { " + " })?;
+ } else if first {
+ write!(self, "Sized")?;
+ }
+
+ Ok(self)
+ }
+
+ /// Insert the trait ref and optionally a projection type associated with it into either the
+ /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
+ fn insert_trait_and_projection(
+ &mut self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
+ traits: &mut FxIndexMap<
+ ty::PolyTraitRef<'tcx>,
+ FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+ >,
+ fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+ ) {
+ let trait_def_id = trait_ref.def_id();
+
+ // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
+ // super-trait ref and record it there.
+ if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
+ // If we have a FnOnce, then insert it into
+ if trait_def_id == fn_once_trait {
+ let entry = fn_traits.entry(trait_ref).or_default();
+ // Optionally insert the return_ty as well.
+ if let Some((_, ty)) = proj_ty {
+ entry.return_ty = Some(ty);
+ }
+ entry.has_fn_once = true;
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_mut_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref);
+ return;
+ }
+ }
+
+ // Otherwise, just group our traits and projection types.
+ traits.entry(trait_ref).or_default().extend(proj_ty);
+ }
+
+ fn pretty_print_bound_var(
+ &mut self,
+ debruijn: ty::DebruijnIndex,
+ var: ty::BoundVar,
+ ) -> Result<(), Self::Error> {
+ if debruijn == ty::INNERMOST {
+ write!(self, "^{}", var.index())
+ } else {
+ write!(self, "^{}_{}", debruijn.index(), var.index())
+ }
+ }
+
+ fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {
+ None
+ }
+
+ fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> {
+ None
+ }
+
+ fn pretty_print_dyn_existential(
+ mut self,
+ predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ // Generate the main trait ref, including associated types.
+ let mut first = true;
+
+ if let Some(principal) = predicates.principal() {
+ self = self.wrap_binder(&principal, |principal, mut cx| {
+ define_scoped_cx!(cx);
+ p!(print_def_path(principal.def_id, &[]));
+
+ let mut resugared = false;
+
+ // Special-case `Fn(...) -> ...` and re-sugar it.
+ let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id);
+ if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() {
+ if let ty::Tuple(tys) = principal.substs.type_at(0).kind() {
+ let mut projections = predicates.projection_bounds();
+ if let (Some(proj), None) = (projections.next(), projections.next()) {
+ p!(pretty_fn_sig(
+ tys,
+ false,
+ proj.skip_binder().term.ty().expect("Return type was a const")
+ ));
+ 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_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0));
+ let principal = principal.with_self_ty(cx.tcx(), dummy_cx);
+
+ let args = cx
+ .tcx()
+ .generics_of(principal.def_id)
+ .own_substs_no_defaults(cx.tcx(), 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.is_erased(),
+ _ => 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)
+ }));
+ }
+ }
+ Ok(cx)
+ })?;
+
+ first = false;
+ }
+
+ define_scoped_cx!(self);
+
+ // 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().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 causing instabilities in compiletest
+ // output, sort the auto-traits alphabetically.
+ auto_traits.sort_by_cached_key(|did| self.tcx().def_path_str(*did));
+
+ for def_id in auto_traits {
+ if !first {
+ p!(" + ");
+ }
+ 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!("(", comma_sep(inputs.iter().copied()));
+ if c_variadic {
+ if !inputs.is_empty() {
+ p!(", ");
+ }
+ p!("...");
+ }
+ p!(")");
+ if !output.is_unit() {
+ p!(" -> ", print(output));
+ }
+
+ Ok(self)
+ }
+
+ fn pretty_print_const(
+ mut self,
+ ct: ty::Const<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ define_scoped_cx!(self);
+
+ if self.tcx().sess.verbose() {
+ p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
+ return Ok(self);
+ }
+
+ macro_rules! print_underscore {
+ () => {{
+ if print_ty {
+ self = self.typed_value(
+ |mut this| {
+ write!(this, "_")?;
+ Ok(this)
+ },
+ |this| this.print_type(ct.ty()),
+ ": ",
+ )?;
+ } else {
+ write!(self, "_")?;
+ }
+ }};
+ }
+
+ match ct.kind() {
+ ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def,
+ substs,
+ promoted: Some(promoted),
+ }) => {
+ p!(print_value_path(def.did, substs));
+ p!(write("::{:?}", promoted));
+ }
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => {
+ match self.tcx().def_kind(def.did) {
+ DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => {
+ p!(print_value_path(def.did, substs))
+ }
+ _ => {
+ if def.is_local() {
+ let span = self.tcx().def_span(def.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(infer_ct) => {
+ match infer_ct {
+ ty::InferConst::Var(ct_vid)
+ if let Some(name) = self.const_infer_name(ct_vid) =>
+ p!(write("{}", name)),
+ _ => print_underscore!(),
+ }
+ }
+ ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
+ ty::ConstKind::Value(value) => {
+ return self.pretty_print_const_valtree(value, ct.ty(), print_ty);
+ }
+
+ ty::ConstKind::Bound(debruijn, bound_var) => {
+ self.pretty_print_bound_var(debruijn, bound_var)?
+ }
+ ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
+ ty::ConstKind::Error(_) => p!("[const error]"),
+ };
+ Ok(self)
+ }
+
+ fn pretty_print_const_scalar(
+ self,
+ scalar: Scalar,
+ ty: Ty<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ match scalar {
+ Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty),
+ Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty),
+ }
+ }
+
+ fn pretty_print_const_scalar_ptr(
+ mut self,
+ ptr: Pointer,
+ ty: Ty<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ define_scoped_cx!(self);
+
+ let (alloc_id, offset) = ptr.into_parts();
+ match ty.kind() {
+ // Byte strings (&[u8; N])
+ ty::Ref(_, inner, _) => {
+ if let ty::Array(elem, len) = inner.kind() {
+ if let ty::Uint(ty::UintTy::U8) = elem.kind() {
+ if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() {
+ match self.tcx().try_get_global_alloc(alloc_id) {
+ Some(GlobalAlloc::Memory(alloc)) => {
+ let len = int.assert_bits(self.tcx().data_layout.pointer_size);
+ let range =
+ AllocRange { start: offset, size: Size::from_bytes(len) };
+ if let Ok(byte_str) =
+ alloc.inner().get_bytes(&self.tcx(), range)
+ {
+ p!(pretty_print_byte_str(byte_str))
+ } else {
+ p!("<too short allocation>")
+ }
+ }
+ // FIXME: for statics, vtables, and functions, we could in principle print more detail.
+ Some(GlobalAlloc::Static(def_id)) => {
+ p!(write("<static({:?})>", def_id))
+ }
+ Some(GlobalAlloc::Function(_)) => p!("<function>"),
+ Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
+ None => p!("<dangling pointer>"),
+ }
+ return Ok(self);
+ }
+ }
+ }
+ }
+ ty::FnPtr(_) => {
+ // FIXME: We should probably have a helper method to share code with the "Byte strings"
+ // printing above (which also has to handle pointers to all sorts of things).
+ if let Some(GlobalAlloc::Function(instance)) =
+ self.tcx().try_get_global_alloc(alloc_id)
+ {
+ self = self.typed_value(
+ |this| this.print_value_path(instance.def_id(), instance.substs),
+ |this| this.print_type(ty),
+ " as ",
+ )?;
+ return Ok(self);
+ }
+ }
+ _ => {}
+ }
+ // Any pointer values not covered by a branch above
+ self = self.pretty_print_const_pointer(ptr, ty, print_ty)?;
+ Ok(self)
+ }
+
+ fn pretty_print_const_scalar_int(
+ mut self,
+ int: ScalarInt,
+ ty: Ty<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ define_scoped_cx!(self);
+
+ match ty.kind() {
+ // Bool
+ ty::Bool if int == ScalarInt::FALSE => p!("false"),
+ ty::Bool if int == ScalarInt::TRUE => p!("true"),
+ // Float
+ ty::Float(ty::FloatTy::F32) => {
+ p!(write("{}f32", Single::try_from(int).unwrap()))
+ }
+ ty::Float(ty::FloatTy::F64) => {
+ p!(write("{}f64", Double::try_from(int).unwrap()))
+ }
+ // Int
+ ty::Uint(_) | ty::Int(_) => {
+ let int =
+ ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral());
+ if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
+ }
+ // Char
+ ty::Char if char::try_from(int).is_ok() => {
+ p!(write("{:?}", char::try_from(int).unwrap()))
+ }
+ // Pointer types
+ ty::Ref(..) | ty::RawPtr(_) | ty::FnPtr(_) => {
+ let data = int.assert_bits(self.tcx().data_layout.pointer_size);
+ self = self.typed_value(
+ |mut this| {
+ write!(this, "0x{:x}", data)?;
+ Ok(this)
+ },
+ |this| this.print_type(ty),
+ " as ",
+ )?;
+ }
+ // Nontrivial types with scalar bit representation
+ _ => {
+ let print = |mut this: Self| {
+ if int.size() == Size::ZERO {
+ write!(this, "transmute(())")?;
+ } else {
+ write!(this, "transmute(0x{:x})", int)?;
+ }
+ Ok(this)
+ };
+ self = if print_ty {
+ self.typed_value(print, |this| this.print_type(ty), ": ")?
+ } else {
+ print(self)?
+ };
+ }
+ }
+ Ok(self)
+ }
+
+ /// This is overridden for MIR printing because we only want to hide alloc ids from users, not
+ /// from MIR where it is actually useful.
+ fn pretty_print_const_pointer<Prov: Provenance>(
+ mut self,
+ _: Pointer<Prov>,
+ ty: Ty<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ if print_ty {
+ self.typed_value(
+ |mut this| {
+ this.write_str("&_")?;
+ Ok(this)
+ },
+ |this| this.print_type(ty),
+ ": ",
+ )
+ } else {
+ self.write_str("&_")?;
+ Ok(self)
+ }
+ }
+
+ fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
+ define_scoped_cx!(self);
+ p!("b\"");
+ for &c in byte_str {
+ for e in std::ascii::escape_default(c) {
+ self.write_char(e as char)?;
+ }
+ }
+ p!("\"");
+ Ok(self)
+ }
+
+ fn pretty_print_const_valtree(
+ mut self,
+ valtree: ty::ValTree<'tcx>,
+ ty: Ty<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ define_scoped_cx!(self);
+
+ if self.tcx().sess.verbose() {
+ p!(write("ValTree({:?}: ", valtree), print(ty), ")");
+ return Ok(self);
+ }
+
+ let u8_type = self.tcx().types.u8;
+ match (valtree, ty.kind()) {
+ (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
+ ty::Slice(t) if *t == u8_type => {
+ let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+ bug!(
+ "expected to convert valtree {:?} to raw bytes for type {:?}",
+ valtree,
+ t
+ )
+ });
+ return self.pretty_print_byte_str(bytes);
+ }
+ ty::Str => {
+ let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+ bug!("expected to convert valtree to raw bytes for type {:?}", ty)
+ });
+ p!(write("{:?}", String::from_utf8_lossy(bytes)));
+ return Ok(self);
+ }
+ _ => {
+ p!("&");
+ p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty));
+ return Ok(self);
+ }
+ },
+ (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
+ let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+ bug!("expected to convert valtree to raw bytes for type {:?}", t)
+ });
+ p!("*");
+ p!(pretty_print_byte_str(bytes));
+ return Ok(self);
+ }
+ // Aggregates, printed as array/tuple/struct/variant construction syntax.
+ (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
+ let contents =
+ self.tcx().destructure_const(ty::Const::from_value(self.tcx(), valtree, ty));
+ let fields = contents.fields.iter().copied();
+ match *ty.kind() {
+ ty::Array(..) => {
+ p!("[", comma_sep(fields), "]");
+ }
+ ty::Tuple(..) => {
+ p!("(", comma_sep(fields));
+ if contents.fields.len() == 1 {
+ p!(",");
+ }
+ p!(")");
+ }
+ ty::Adt(def, _) if def.variants().is_empty() => {
+ self = self.typed_value(
+ |mut this| {
+ write!(this, "unreachable()")?;
+ Ok(this)
+ },
+ |this| this.print_type(ty),
+ ": ",
+ )?;
+ }
+ ty::Adt(def, substs) => {
+ let variant_idx =
+ contents.variant.expect("destructed const of adt without variant idx");
+ let variant_def = &def.variant(variant_idx);
+ p!(print_value_path(variant_def.def_id, substs));
+ match variant_def.ctor_kind {
+ CtorKind::Const => {}
+ CtorKind::Fn => {
+ p!("(", comma_sep(fields), ")");
+ }
+ CtorKind::Fictive => {
+ p!(" {{ ");
+ let mut first = true;
+ for (field_def, field) in iter::zip(&variant_def.fields, fields) {
+ if !first {
+ p!(", ");
+ }
+ p!(write("{}: ", field_def.name), print(field));
+ first = false;
+ }
+ p!(" }}");
+ }
+ }
+ }
+ _ => unreachable!(),
+ }
+ return Ok(self);
+ }
+ (ty::ValTree::Leaf(leaf), _) => {
+ return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
+ }
+ // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
+ // their fields instead of just dumping the memory.
+ _ => {}
+ }
+
+ // fallback
+ if valtree == ty::ValTree::zst() {
+ p!(write("<ZST>"));
+ } else {
+ p!(write("{:?}", valtree));
+ }
+ if print_ty {
+ p!(": ", print(ty));
+ }
+ Ok(self)
+ }
+}
+
+// HACK(eddyb) boxed to avoid moving around a large struct by-value.
+pub struct FmtPrinter<'a, 'tcx>(Box<FmtPrinterData<'a, 'tcx>>);
+
+pub struct FmtPrinterData<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ fmt: String,
+
+ empty_path: bool,
+ in_value: bool,
+ pub print_alloc_ids: bool,
+
+ used_region_names: FxHashSet<Symbol>,
+ region_index: usize,
+ binder_depth: usize,
+ printed_type_count: usize,
+
+ pub region_highlight_mode: RegionHighlightMode<'tcx>,
+
+ pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>,
+ pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>,
+}
+
+impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> {
+ type Target = FmtPrinterData<'a, 'tcx>;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl DerefMut for FmtPrinter<'_, '_> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>, ns: Namespace) -> Self {
+ FmtPrinter(Box::new(FmtPrinterData {
+ tcx,
+ // Estimated reasonable capacity to allocate upfront based on a few
+ // benchmarks.
+ fmt: String::with_capacity(64),
+ empty_path: false,
+ in_value: ns == Namespace::ValueNS,
+ print_alloc_ids: false,
+ used_region_names: Default::default(),
+ region_index: 0,
+ binder_depth: 0,
+ printed_type_count: 0,
+ region_highlight_mode: RegionHighlightMode::new(tcx),
+ ty_infer_name_resolver: None,
+ const_infer_name_resolver: None,
+ }))
+ }
+
+ pub fn into_buffer(self) -> String {
+ self.0.fmt
+ }
+}
+
+// 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<'t> 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);
+ FmtPrinter::new(self, ns).print_def_path(def_id, substs).unwrap().into_buffer()
+ }
+}
+
+impl fmt::Write for FmtPrinter<'_, '_> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.fmt.push_str(s);
+ Ok(())
+ }
+}
+
+impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
+ type Error = fmt::Error;
+
+ type Path = Self;
+ type Region = Self;
+ type Type = Self;
+ type DynExistential = Self;
+ type Const = Self;
+
+ fn tcx<'a>(&'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_trimmed_def_path(def_id)? {
+ (cx, true) => return Ok(cx),
+ (cx, false) => self = cx,
+ }
+
+ 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 {}>",
+ // This may end up in stderr diagnostics but it may also be emitted
+ // into MIR. Hence we use the remapped path if available
+ self.tcx.sess.source_map().span_to_embeddable_string(span)
+ )?;
+ self.empty_path = false;
+
+ return Ok(self);
+ }
+ }
+
+ self.default_print_def_path(def_id, substs)
+ }
+
+ fn print_region(self, region: ty::Region<'tcx>) -> Result<Self::Region, Self::Error> {
+ self.pretty_print_region(region)
+ }
+
+ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+ let type_length_limit = self.tcx.type_length_limit();
+ if type_length_limit.value_within_limit(self.printed_type_count) {
+ self.printed_type_count += 1;
+ self.pretty_print_type(ty)
+ } else {
+ write!(self, "...")?;
+ Ok(self)
+ }
+ }
+
+ fn print_dyn_existential(
+ self,
+ predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ self.pretty_print_dyn_existential(predicates)
+ }
+
+ fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ self.pretty_print_const(ct, false)
+ }
+
+ 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 `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
+ if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
+ return Ok(self);
+ }
+
+ let name = disambiguated_data.data.name();
+ if !self.empty_path {
+ write!(self, "::")?;
+ }
+
+ if let DefPathDataName::Named(name) = name {
+ if Ident::with_dummy_span(name).is_raw_guess() {
+ write!(self, "r#")?;
+ }
+ }
+
+ let verbose = self.tcx.sess.verbose();
+ disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?;
+
+ 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 = self.tcx.sess.verbose()
+ || args.iter().any(|arg| match arg.unpack() {
+ GenericArgKind::Lifetime(r) => !r.is_erased(),
+ _ => 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<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
+ fn ty_infer_name(&self, id: ty::TyVid) -> Option<Symbol> {
+ self.0.ty_infer_name_resolver.as_ref().and_then(|func| func(id))
+ }
+
+ fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> {
+ self.0.const_infer_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<'tcx, T>) -> Result<Self, Self::Error>
+ where
+ T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
+ {
+ self.pretty_in_binder(value)
+ }
+
+ fn wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, Self::Error>>(
+ self,
+ value: &ty::Binder<'tcx, T>,
+ f: C,
+ ) -> Result<Self, Self::Error>
+ where
+ T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>,
+ {
+ self.pretty_wrap_binder(value, f)
+ }
+
+ fn typed_value(
+ mut self,
+ f: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ t: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ conversion: &str,
+ ) -> Result<Self::Const, Self::Error> {
+ self.write_str("{")?;
+ self = f(self)?;
+ self.write_str(conversion)?;
+ let was_in_value = std::mem::replace(&mut self.in_value, false);
+ self = t(self)?;
+ self.in_value = was_in_value;
+ self.write_str("}")?;
+ Ok(self)
+ }
+
+ 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 should_print_region(&self, region: ty::Region<'tcx>) -> 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.unstable_opts.identify_regions;
+
+ match *region {
+ ty::ReEarlyBound(ref data) => {
+ data.name != kw::Empty && data.name != kw::UnderscoreLifetime
+ }
+
+ ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+ | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
+ | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
+ if let ty::BrNamed(_, name) = br {
+ if name != kw::Empty && name != kw::UnderscoreLifetime {
+ return true;
+ }
+ }
+
+ if let Some((region, _)) = highlight.highlight_bound_region {
+ if br == region {
+ return true;
+ }
+ }
+
+ false
+ }
+
+ ty::ReVar(_) if identify_regions => true,
+
+ ty::ReVar(_) | ty::ReErased => false,
+
+ ty::ReStatic | ty::ReEmpty(_) => true,
+ }
+ }
+
+ fn pretty_print_const_pointer<Prov: Provenance>(
+ self,
+ p: Pointer<Prov>,
+ ty: Ty<'tcx>,
+ print_ty: bool,
+ ) -> Result<Self::Const, Self::Error> {
+ let print = |mut this: Self| {
+ define_scoped_cx!(this);
+ if this.print_alloc_ids {
+ p!(write("{:?}", p));
+ } else {
+ p!("&_");
+ }
+ Ok(this)
+ };
+ if print_ty {
+ self.typed_value(print, |this| this.print_type(ty), ": ")
+ } else {
+ print(self)
+ }
+ }
+}
+
+// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
+impl<'tcx> FmtPrinter<'_, 'tcx> {
+ pub fn pretty_print_region(mut self, region: ty::Region<'tcx>) -> 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.unstable_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::Empty {
+ p!(write("{}", data.name));
+ return Ok(self);
+ }
+ }
+ ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+ | ty::ReFree(ty::FreeRegion { bound_region: br, .. })
+ | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
+ if let ty::BrNamed(_, name) = br {
+ if name != kw::Empty && 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::ReVar(region_vid) if identify_regions => {
+ p!(write("{:?}", region_vid));
+ return Ok(self);
+ }
+ ty::ReVar(_) => {}
+ ty::ReErased => {}
+ ty::ReStatic => {
+ p!("'static");
+ return Ok(self);
+ }
+ ty::ReEmpty(ty::UniverseIndex::ROOT) => {
+ p!("'<empty>");
+ return Ok(self);
+ }
+ ty::ReEmpty(ui) => {
+ p!(write("'<empty:{:?}>", ui));
+ return Ok(self);
+ }
+ }
+
+ p!("'_");
+
+ Ok(self)
+ }
+}
+
+/// Folds through bound vars and placeholders, naming them
+struct RegionFolder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ current_index: ty::DebruijnIndex,
+ region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
+ name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+}
+
+impl<'a, 'tcx> ty::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<'tcx, T>,
+ ) -> ty::Binder<'tcx, 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() {
+ _ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
+ return t.super_fold_with(self);
+ }
+ _ => {}
+ }
+ t
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ let name = &mut self.name;
+ let region = match *r {
+ ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)),
+ ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
+ // If this is an anonymous placeholder, don't rename. Otherwise, in some
+ // async fns, we get a `for<'r> Send` bound
+ match kind {
+ ty::BrAnon(_) | ty::BrEnv => r,
+ _ => {
+ // Index doesn't matter, since this is just for naming and these never get bound
+ let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
+ *self.region_map.entry(br).or_insert_with(|| name(br))
+ }
+ }
+ }
+ _ => return r,
+ };
+ if let ty::ReLateBound(debruijn1, br) = *region {
+ assert_eq!(debruijn1, ty::INNERMOST);
+ self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
+ } else {
+ region
+ }
+ }
+}
+
+// HACK(eddyb) limited to `FmtPrinter` because of `binder_depth`,
+// `region_index` and `used_region_names`.
+impl<'tcx> FmtPrinter<'_, 'tcx> {
+ pub fn name_all_regions<T>(
+ mut self,
+ value: &ty::Binder<'tcx, 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| {
+ let w = if empty {
+ empty = false;
+ start
+ } else {
+ cont
+ };
+ let _ = write!(cx, "{}", w);
+ };
+ let do_continue = |cx: &mut Self, cont: Symbol| {
+ let _ = write!(cx, "{}", cont);
+ };
+
+ define_scoped_cx!(self);
+
+ let mut region_index = self.region_index;
+ let mut next_name = |this: &Self| loop {
+ let name = name_by_region_index(region_index);
+ region_index += 1;
+ if !this.used_region_names.contains(&name) {
+ break name;
+ }
+ };
+
+ // If we want to print verbosely, then print *all* binders, even if they
+ // aren't named. Eventually, we might just want this as the default, but
+ // this is not *quite* right and changes the ordering of some output
+ // anyways.
+ let (new_value, map) = if self.tcx().sess.verbose() {
+ let regions: Vec<_> = value
+ .bound_vars()
+ .into_iter()
+ .map(|var| {
+ let ty::BoundVariableKind::Region(var) = var else {
+ // This doesn't really matter because it doesn't get used,
+ // it's just an empty value
+ return ty::BrAnon(0);
+ };
+ match var {
+ ty::BrAnon(_) | ty::BrEnv => {
+ start_or_continue(&mut self, "for<", ", ");
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+ }
+ ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+ start_or_continue(&mut self, "for<", ", ");
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(def_id, name)
+ }
+ ty::BrNamed(def_id, name) => {
+ start_or_continue(&mut self, "for<", ", ");
+ do_continue(&mut self, name);
+ ty::BrNamed(def_id, name)
+ }
+ }
+ })
+ .collect();
+ start_or_continue(&mut self, "", "> ");
+
+ self.tcx.replace_late_bound_regions(value.clone(), |br| {
+ let kind = regions[br.var.as_usize()];
+ self.tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: br.var, kind },
+ ))
+ })
+ } else {
+ let tcx = self.tcx;
+ let mut name = |br: ty::BoundRegion| {
+ start_or_continue(&mut self, "for<", ", ");
+ let kind = match br.kind {
+ ty::BrAnon(_) | ty::BrEnv => {
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+ }
+ ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(def_id, name)
+ }
+ ty::BrNamed(_, name) => {
+ do_continue(&mut self, name);
+ br.kind
+ }
+ };
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
+ };
+ let mut folder = RegionFolder {
+ tcx,
+ current_index: ty::INNERMOST,
+ name: &mut name,
+ region_map: BTreeMap::new(),
+ };
+ let new_value = value.clone().skip_binder().fold_with(&mut folder);
+ let region_map = folder.region_map;
+ start_or_continue(&mut self, "", "> ");
+ (new_value, region_map)
+ };
+
+ self.binder_depth += 1;
+ self.region_index = region_index;
+ Ok((self, new_value, map))
+ }
+
+ pub fn pretty_in_binder<T>(self, value: &ty::Binder<'tcx, 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.print(new)?;
+ inner.region_index = old_region_index;
+ inner.binder_depth -= 1;
+ Ok(inner)
+ }
+
+ pub fn pretty_wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, fmt::Error>>(
+ self,
+ value: &ty::Binder<'tcx, T>,
+ f: C,
+ ) -> 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 = f(&new_value, 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<'tcx, T>)
+ where
+ T: TypeVisitable<'tcx>,
+ {
+ struct LateBoundRegionNameCollector<'a, 'tcx> {
+ used_region_names: &'a mut FxHashSet<Symbol>,
+ type_collector: SsoHashSet<Ty<'tcx>>,
+ }
+
+ impl<'tcx> ty::visit::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
+ type BreakTy = ();
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ trace!("address: {:p}", r.0.0);
+ if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
+ self.used_region_names.insert(name);
+ } else if let ty::RePlaceholder(ty::PlaceholderRegion {
+ name: ty::BrNamed(_, name),
+ ..
+ }) = *r
+ {
+ self.used_region_names.insert(name);
+ }
+ r.super_visit_with(self)
+ }
+
+ // We collect types in order to prevent really large types from compiling for
+ // a really long time. See issue #83150 for why this is necessary.
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let not_previously_inserted = self.type_collector.insert(ty);
+ if not_previously_inserted {
+ ty.super_visit_with(self)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+
+ self.used_region_names.clear();
+ let mut collector = LateBoundRegionNameCollector {
+ used_region_names: &mut self.used_region_names,
+ type_collector: SsoHashSet::new(),
+ };
+ value.visit_with(&mut collector);
+ self.region_index = 0;
+ }
+}
+
+impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, 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), ": ", print(self.1));
+ Ok(cx)
+ }
+}
+
+macro_rules! forward_display_to_print {
+ ($($ty:ty),+) => {
+ // Some of the $ty arguments may not actually use 'tcx
+ $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ ty::tls::with(|tcx| {
+ let cx = tcx.lift(*self)
+ .expect("could not lift for printing")
+ .print(FmtPrinter::new(tcx, Namespace::TypeNS))?;
+ f.write_str(&cx.into_buffer())?;
+ 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),+);
+ };
+}
+
+/// 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, TypeVisitable, Lift)]
+pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
+
+impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
+/// the trait name. That is, it will print `Trait` instead of
+/// `<T as Trait<U>>`.
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>);
+
+impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl<'tcx> ty::TraitRef<'tcx> {
+ pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
+ TraitRefPrintOnlyTraitPath(self)
+ }
+
+ pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
+ TraitRefPrintOnlyTraitName(self)
+ }
+}
+
+impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
+ pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
+ self.map_bound(|tr| tr.print_only_trait_path())
+ }
+}
+
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);
+
+impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl<'tcx> ty::TraitPredicate<'tcx> {
+ pub fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> {
+ TraitPredPrintModifiersAndPath(self)
+ }
+}
+
+impl<'tcx> ty::PolyTraitPredicate<'tcx> {
+ pub fn print_modifiers_and_trait_path(
+ self,
+ ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
+ self.map_bound(TraitPredPrintModifiersAndPath)
+ }
+}
+
+forward_display_to_print! {
+ ty::Region<'tcx>,
+ Ty<'tcx>,
+ &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ ty::Const<'tcx>,
+
+ // HACK(eddyb) these are exhaustive instead of generic,
+ // because `for<'tcx>` isn't possible yet.
+ ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>,
+ ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>,
+ ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
+ ty::Binder<'tcx, ty::FnSig<'tcx>>,
+ ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
+ ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
+ ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
+ ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
+ ty::Binder<'tcx, 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!("{{", comma_sep(self.iter()), "}}")
+ }
+
+ 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).name;
+ p!(write("{} = ", name), print(self.term))
+ }
+
+ 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!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+ }
+
+ 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));
+ }
+
+ TraitRefPrintOnlyTraitName<'tcx> {
+ p!(print_def_path(self.0.def_id, &[]));
+ }
+
+ TraitPredPrintModifiersAndPath<'tcx> {
+ if let ty::BoundConstness::ConstIfConst = self.0.constness {
+ p!("~const ")
+ }
+
+ if let ty::ImplPolarity::Negative = self.0.polarity {
+ p!("!")
+ }
+
+ p!(print(self.0.trait_ref.print_only_trait_path()));
+ }
+
+ ty::ParamTy {
+ p!(write("{}", self.name))
+ }
+
+ ty::ParamConst {
+ p!(write("{}", self.name))
+ }
+
+ ty::SubtypePredicate<'tcx> {
+ p!(print(self.a), " <: ", print(self.b))
+ }
+
+ ty::CoercePredicate<'tcx> {
+ p!(print(self.a), " -> ", print(self.b))
+ }
+
+ ty::TraitPredicate<'tcx> {
+ p!(print(self.trait_ref.self_ty()), ": ");
+ if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
+ p!("~const ");
+ }
+ p!(print(self.trait_ref.print_only_trait_path()))
+ }
+
+ ty::ProjectionPredicate<'tcx> {
+ p!(print(self.projection_ty), " == ", print(self.term))
+ }
+
+ ty::Term<'tcx> {
+ match self {
+ ty::Term::Ty(ty) => p!(print(ty)),
+ ty::Term::Const(c) => p!(print(c)),
+ }
+ }
+
+ ty::ProjectionTy<'tcx> {
+ p!(print_def_path(self.item_def_id, self.substs));
+ }
+
+ ty::ClosureKind {
+ match *self {
+ ty::ClosureKind::Fn => p!("Fn"),
+ ty::ClosureKind::FnMut => p!("FnMut"),
+ ty::ClosureKind::FnOnce => p!("FnOnce"),
+ }
+ }
+
+ ty::Predicate<'tcx> {
+ let binder = self.kind();
+ p!(print(binder))
+ }
+
+ ty::PredicateKind<'tcx> {
+ match *self {
+ ty::PredicateKind::Trait(ref data) => {
+ p!(print(data))
+ }
+ ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+ ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
+ ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
+ ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
+ ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
+ ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
+ }
+ ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => {
+ p!("the closure `",
+ print_value_path(closure_def_id, &[]),
+ write("` implements the trait `{}`", kind))
+ }
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
+ }
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ p!("the constant `", print(c1), "` equals `", print(c2), "`")
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+ p!("the type `", print(ty), "` is found in the environment")
+ }
+ }
+ }
+
+ GenericArg<'tcx> {
+ match self.unpack() {
+ GenericArgKind::Lifetime(lt) => p!(print(lt)),
+ GenericArgKind::Type(ty) => p!(print(ty)),
+ GenericArgKind::Const(ct) => p!(print(ct)),
+ }
+ }
+}
+
+fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
+ // Iterate all local crate items no matter where they are defined.
+ let hir = tcx.hir();
+ for id in hir.items() {
+ if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
+ continue;
+ }
+
+ let item = hir.item(id);
+ if item.ident.name == kw::Empty {
+ continue;
+ }
+
+ let def_id = item.def_id.to_def_id();
+ let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
+ collect_fn(&item.ident, ns, def_id);
+ }
+
+ // Now take care of extern crate items.
+ let queue = &mut Vec::new();
+ let mut seen_defs: DefIdSet = Default::default();
+
+ for &cnum in tcx.crates(()).iter() {
+ let def_id = cnum.as_def_id();
+
+ // Ignore crates that are not direct dependencies.
+ match tcx.extern_crate(def_id) {
+ None => continue,
+ Some(extern_crate) => {
+ if !extern_crate.is_direct() {
+ continue;
+ }
+ }
+ }
+
+ queue.push(def_id);
+ }
+
+ // Iterate external crate defs but be mindful about visibility
+ while let Some(def) = queue.pop() {
+ for child in tcx.module_children(def).iter() {
+ if !child.vis.is_public() {
+ continue;
+ }
+
+ match child.res {
+ def::Res::Def(DefKind::AssocTy, _) => {}
+ def::Res::Def(DefKind::TyAlias, _) => {}
+ def::Res::Def(defkind, def_id) => {
+ if let Some(ns) = defkind.ns() {
+ collect_fn(&child.ident, ns, def_id);
+ }
+
+ if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait)
+ && seen_defs.insert(def_id)
+ {
+ queue.push(def_id);
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+}
+
+/// The purpose of this function is to collect public symbols names that are unique across all
+/// crates in the build. Later, when printing about types we can use those names instead of the
+/// full exported path to them.
+///
+/// So essentially, if a symbol name can only be imported from one place for a type, and as
+/// long as it was not glob-imported anywhere in the current crate, we can trim its printed
+/// path and print only the name.
+///
+/// This has wide implications on error messages with types, for example, shortening
+/// `std::vec::Vec` to just `Vec`, as long as there is no other `Vec` importable anywhere.
+///
+/// The implementation uses similar import discovery logic to that of 'use' suggestions.
+fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
+ let mut map: FxHashMap<DefId, Symbol> = FxHashMap::default();
+
+ if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths {
+ // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths`
+ // wrapper can be used to suppress this query, in exchange for full paths being formatted.
+ tcx.sess.delay_good_path_bug("trimmed_def_paths constructed");
+ }
+
+ let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option<DefId>> =
+ &mut FxHashMap::default();
+
+ for symbol_set in tcx.resolutions(()).glob_map.values() {
+ for symbol in symbol_set {
+ unique_symbols_rev.insert((Namespace::TypeNS, *symbol), None);
+ unique_symbols_rev.insert((Namespace::ValueNS, *symbol), None);
+ unique_symbols_rev.insert((Namespace::MacroNS, *symbol), None);
+ }
+ }
+
+ for_each_def(tcx, |ident, ns, def_id| {
+ use std::collections::hash_map::Entry::{Occupied, Vacant};
+
+ match unique_symbols_rev.entry((ns, ident.name)) {
+ Occupied(mut v) => match v.get() {
+ None => {}
+ Some(existing) => {
+ if *existing != def_id {
+ v.insert(None);
+ }
+ }
+ },
+ Vacant(v) => {
+ v.insert(Some(def_id));
+ }
+ }
+ });
+
+ for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() {
+ use std::collections::hash_map::Entry::{Occupied, Vacant};
+
+ if let Some(def_id) = opt_def_id {
+ match map.entry(def_id) {
+ Occupied(mut v) => {
+ // A single DefId can be known under multiple names (e.g.,
+ // with a `pub use ... as ...;`). We need to ensure that the
+ // name placed in this map is chosen deterministically, so
+ // if we find multiple names (`symbol`) resolving to the
+ // same `def_id`, we prefer the lexicographically smallest
+ // name.
+ //
+ // Any stable ordering would be fine here though.
+ if *v.get() != symbol {
+ if v.get().as_str() > symbol.as_str() {
+ v.insert(symbol);
+ }
+ }
+ }
+ Vacant(v) => {
+ v.insert(symbol);
+ }
+ }
+ }
+ }
+
+ map
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { trimmed_def_paths, ..*providers };
+}
+
+#[derive(Default)]
+pub struct OpaqueFnEntry<'tcx> {
+ // The trait ref is already stored as a key, so just track if we have it as a real predicate
+ has_fn_once: bool,
+ fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+ fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+ return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
+}
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
new file mode 100644
index 000000000..2452bcf6a
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -0,0 +1,386 @@
+use crate::dep_graph;
+use crate::infer::canonical::{self, Canonical};
+use crate::lint::LintLevelMap;
+use crate::metadata::ModChild;
+use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
+use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use crate::middle::lib_features::LibFeatures;
+use crate::middle::privacy::AccessLevels;
+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::{
+ ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
+};
+use crate::mir::interpret::{LitToConstError, LitToConstInput};
+use crate::mir::mono::CodegenUnit;
+use crate::thir;
+use crate::traits::query::{
+ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
+ CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
+ CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
+};
+use crate::traits::query::{
+ DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult,
+ OutlivesBound,
+};
+use crate::traits::specialization_graph;
+use crate::traits::{self, ImplSource};
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::layout::TyAndLayout;
+use crate::ty::subst::{GenericArg, SubstsRef};
+use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
+use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use rustc_ast as ast;
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::steal::Steal;
+use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
+use rustc_hir::lang_items::{LangItem, LanguageItems};
+use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
+use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
+use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
+use rustc_session::cstore::{CrateDepKind, CrateSource};
+use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
+use rustc_session::utils::NativeLibKind;
+use rustc_session::Limits;
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
+use std::ops::Deref;
+use std::path::PathBuf;
+use std::sync::Arc;
+
+pub(crate) use rustc_query_system::query::QueryJobId;
+use rustc_query_system::query::*;
+
+#[derive(Copy, Clone)]
+pub struct TyCtxtAt<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+ pub span: Span,
+}
+
+impl<'tcx> Deref for TyCtxtAt<'tcx> {
+ type Target = TyCtxt<'tcx>;
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.tcx
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct TyCtxtEnsure<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
+ /// are executed instead of just returning 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 }
+ }
+
+ pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
+ self.queries.try_mark_green(self, dep_node)
+ }
+}
+
+/// Helper for `TyCtxtEnsure` to avoid a closure.
+#[inline(always)]
+fn noop<T>(_: &T) {}
+
+/// Helper to ensure that queries only return `Copy` types.
+#[inline(always)]
+fn copy<T: Copy>(x: &T) -> T {
+ *x
+}
+
+macro_rules! query_helper_param_ty {
+ (DefId) => { impl IntoQueryParam<DefId> };
+ ($K:ty) => { $K };
+}
+
+macro_rules! query_storage {
+ ([][$K:ty, $V:ty]) => {
+ <DefaultCacheSelector as CacheSelector<$K, $V>>::Cache
+ };
+ ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
+ <$ty as CacheSelector<$K, $V>>::Cache
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ query_storage!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! separate_provide_extern_decl {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ for<'tcx> fn(
+ TyCtxt<'tcx>,
+ query_keys::$name<'tcx>,
+ ) -> query_values::$name<'tcx>
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_decl!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! separate_provide_extern_default {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ |_, key| bug!(
+ "`tcx.{}({:?})` unsupported by its crate; \
+ perhaps the `{}` query was never assigned a provider function",
+ stringify!($name),
+ key,
+ stringify!($name),
+ )
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_default!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! opt_remap_env_constness {
+ ([][$name:ident]) => {};
+ ([(remap_env_constness) $($rest:tt)*][$name:ident]) => {
+ let $name = $name.without_const();
+ };
+ ([$other:tt $($modifiers:tt)*][$name:ident]) => {
+ opt_remap_env_constness!([$($modifiers)*][$name])
+ };
+}
+
+macro_rules! define_callbacks {
+ (<$tcx:tt>
+ $($(#[$attr:meta])*
+ [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
+
+ // HACK(eddyb) this is like the `impl QueryConfig for queries::$name`
+ // below, but using type aliases instead of associated types, to bypass
+ // the limitations around normalizing under HRTB - for example, this:
+ // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value`
+ // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`.
+ // This is primarily used by the `provide!` macro in `rustc_metadata`.
+ #[allow(nonstandard_style, unused_lifetimes)]
+ pub mod query_keys {
+ use super::*;
+
+ $(pub type $name<$tcx> = $($K)*;)*
+ }
+ #[allow(nonstandard_style, unused_lifetimes)]
+ pub mod query_values {
+ use super::*;
+
+ $(pub type $name<$tcx> = $V;)*
+ }
+ #[allow(nonstandard_style, unused_lifetimes)]
+ pub mod query_storage {
+ use super::*;
+
+ $(pub type $name<$tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
+ }
+ #[allow(nonstandard_style, unused_lifetimes)]
+ pub mod query_stored {
+ use super::*;
+
+ $(pub type $name<$tcx> = <query_storage::$name<$tcx> as QueryStorage>::Stored;)*
+ }
+
+ #[derive(Default)]
+ pub struct QueryCaches<$tcx> {
+ $($(#[$attr])* pub $name: query_storage::$name<$tcx>,)*
+ }
+
+ impl<$tcx> TyCtxtEnsure<$tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+ let key = key.into_query_param();
+ opt_remap_env_constness!([$($modifiers)*][key]);
+
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
+
+ match cached {
+ Ok(()) => return,
+ Err(()) => (),
+ }
+
+ self.tcx.queries.$name(self.tcx, DUMMY_SP, key, QueryMode::Ensure);
+ })*
+ }
+
+ impl<$tcx> TyCtxt<$tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ #[must_use]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
+ {
+ self.at(DUMMY_SP).$name(key)
+ })*
+ }
+
+ impl<$tcx> TyCtxtAt<$tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
+ {
+ let key = key.into_query_param();
+ opt_remap_env_constness!([$($modifiers)*][key]);
+
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, copy);
+
+ match cached {
+ Ok(value) => return value,
+ Err(()) => (),
+ }
+
+ self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap()
+ })*
+ }
+
+ pub struct Providers {
+ $(pub $name: for<'tcx> fn(
+ TyCtxt<'tcx>,
+ query_keys::$name<'tcx>,
+ ) -> query_values::$name<'tcx>,)*
+ }
+
+ pub struct ExternProviders {
+ $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
+ }
+
+ impl Default for Providers {
+ fn default() -> Self {
+ Providers {
+ $($name: |_, key| bug!(
+ "`tcx.{}({:?})` unsupported by its crate; \
+ perhaps the `{}` query was never assigned a provider function",
+ stringify!($name),
+ key,
+ stringify!($name),
+ ),)*
+ }
+ }
+ }
+
+ impl Default for ExternProviders {
+ fn default() -> Self {
+ ExternProviders {
+ $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
+ }
+ }
+ }
+
+ impl Copy for Providers {}
+ impl Clone for Providers {
+ fn clone(&self) -> Self { *self }
+ }
+
+ impl Copy for ExternProviders {}
+ impl Clone for ExternProviders {
+ fn clone(&self) -> Self { *self }
+ }
+
+ pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
+ fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
+
+ fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool;
+
+ $($(#[$attr])*
+ fn $name(
+ &'tcx self,
+ tcx: TyCtxt<$tcx>,
+ span: Span,
+ key: query_keys::$name<$tcx>,
+ mode: QueryMode,
+ ) -> Option<query_stored::$name<$tcx>>;)*
+ }
+ };
+}
+
+// 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_callbacks!][<'tcx>] }
+
+mod sealed {
+ use super::{DefId, LocalDefId};
+
+ /// An analogue of the `Into` trait that's intended only for query parameters.
+ ///
+ /// This exists to allow queries to accept either `DefId` or `LocalDefId` while requiring that the
+ /// user call `to_def_id` to convert between them everywhere else.
+ pub trait IntoQueryParam<P> {
+ fn into_query_param(self) -> P;
+ }
+
+ impl<P> IntoQueryParam<P> for P {
+ #[inline(always)]
+ fn into_query_param(self) -> P {
+ self
+ }
+ }
+
+ impl<'a, P: Copy> IntoQueryParam<P> for &'a P {
+ #[inline(always)]
+ fn into_query_param(self) -> P {
+ *self
+ }
+ }
+
+ impl IntoQueryParam<DefId> for LocalDefId {
+ #[inline(always)]
+ fn into_query_param(self) -> DefId {
+ self.to_def_id()
+ }
+ }
+}
+
+use sealed::IntoQueryParam;
+
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
+ let def_id = def_id.into_query_param();
+ self.opt_def_kind(def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
+ }
+}
+
+impl<'tcx> TyCtxtAt<'tcx> {
+ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
+ let def_id = def_id.into_query_param();
+ self.opt_def_kind(def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
new file mode 100644
index 000000000..818affa71
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -0,0 +1,841 @@
+//! 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::ty::error::{ExpectedFound, TypeError};
+use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
+use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
+use rustc_hir as ast;
+use rustc_hir::def_id::DefId;
+use rustc_span::DUMMY_SP;
+use rustc_target::spec::abi;
+use std::iter;
+
+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 tcx = self.tcx();
+ let opt_variances = tcx.variances_of(item_def_id);
+ relate_substs_with_variances(self, item_def_id, 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,
+ info: ty::VarianceDiagInfo<'tcx>,
+ a: T,
+ b: T,
+ ) -> RelateResult<'tcx, T>;
+
+ // Overridable 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: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>>;
+
+ fn binders<T>(
+ &mut self,
+ a: ty::Binder<'tcx, T>,
+ b: ty::Binder<'tcx, T>,
+ ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+ where
+ T: Relate<'tcx>;
+}
+
+pub trait Relate<'tcx>: TypeFoldable<'tcx> + Copy {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: Self,
+ b: Self,
+ ) -> RelateResult<'tcx, Self>;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Relate impls
+
+pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::TypeAndMut<'tcx>,
+ b: ty::TypeAndMut<'tcx>,
+ base_ty: Ty<'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, info) = match mutbl {
+ ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+ ast::Mutability::Mut => {
+ (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 })
+ }
+ };
+ let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
+ Ok(ty::TypeAndMut { ty, mutbl })
+ }
+}
+
+#[inline]
+pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a_subst: SubstsRef<'tcx>,
+ b_subst: SubstsRef<'tcx>,
+) -> RelateResult<'tcx, SubstsRef<'tcx>> {
+ relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| {
+ relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
+ }))
+}
+
+pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ ty_def_id: DefId,
+ variances: &[ty::Variance],
+ a_subst: SubstsRef<'tcx>,
+ b_subst: SubstsRef<'tcx>,
+) -> RelateResult<'tcx, SubstsRef<'tcx>> {
+ let tcx = relation.tcx();
+
+ let mut cached_ty = None;
+ let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
+ let variance = variances[i];
+ let variance_info = if variance == ty::Invariant {
+ let ty =
+ *cached_ty.get_or_insert_with(|| tcx.bound_type_of(ty_def_id).subst(tcx, a_subst));
+ ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+ } else {
+ ty::VarianceDiagInfo::default()
+ };
+ relation.relate_with_variance(variance, variance_info, a, b)
+ });
+
+ 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 = iter::zip(a.inputs(), b.inputs())
+ .map(|(&a, &b)| ((a, b), 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,
+ ty::VarianceDiagInfo::default(),
+ a,
+ b,
+ )
+ }
+ })
+ .enumerate()
+ .map(|(i, r)| match r {
+ Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
+ Err(TypeError::ArgumentSorts(exp_found, i))
+ }
+ Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
+ Err(TypeError::ArgumentMutability(i))
+ }
+ r => r,
+ });
+ 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 ty::BoundConstness {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::BoundConstness,
+ b: ty::BoundConstness,
+ ) -> RelateResult<'tcx, ty::BoundConstness> {
+ if a != b {
+ Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+}
+
+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 term = relation.relate_with_variance(
+ ty::Invariant,
+ ty::VarianceDiagInfo::default(),
+ a.term,
+ b.term,
+ )?;
+ let substs = relation.relate_with_variance(
+ ty::Invariant,
+ ty::VarianceDiagInfo::default(),
+ a.substs,
+ b.substs,
+ )?;
+ Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
+ }
+ }
+}
+
+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, a.substs, b.substs)?;
+ Ok(ty::TraitRef { def_id: a.def_id, 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, a.substs, b.substs)?;
+ Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs })
+ }
+ }
+}
+
+#[derive(Copy, Debug, Clone, TypeFoldable, TypeVisitable)]
+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(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?;
+ Ok(GeneratorWitness(types))
+ }
+}
+
+impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> {
+ #[inline]
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ImplSubject<'tcx>,
+ b: ImplSubject<'tcx>,
+ ) -> RelateResult<'tcx, ImplSubject<'tcx>> {
+ match (a, b) {
+ (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
+ let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
+ Ok(ImplSubject::Trait(trait_ref))
+ }
+ (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
+ let ty = Ty::relate(relation, ty_a, ty_b)?;
+ Ok(ImplSubject::Inherent(ty))
+ }
+ (ImplSubject::Trait(_), ImplSubject::Inherent(_))
+ | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
+ bug!("can not relate TraitRef and Ty");
+ }
+ }
+ }
+}
+
+impl<'tcx> Relate<'tcx> for Ty<'tcx> {
+ #[inline]
+ 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<'tcx, 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.ty_error()),
+
+ (&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(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
+ let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
+ relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ 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(a_mt), &ty::RawPtr(b_mt)) => {
+ let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
+ 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,
+ ty::VarianceDiagInfo::default(),
+ 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 = relate_type_and_mut(relation, a_mt, b_mt, a)?;
+ 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.
+ //
+ // It might seem dubious to eagerly evaluate these constants here,
+ // we however cannot end up with errors in `Relate` during both
+ // `type_of` and `predicates_of`. This means that evaluating the
+ // constants should not cause cycle errors here.
+ 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)) if sz_a_val != sz_b_val => Err(
+ TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)),
+ ),
+ _ => 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(iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)))?)
+ } 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))
+ }
+
+ // 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, 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<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+) -> RelateResult<'tcx, ty::Const<'tcx>> {
+ debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
+ let tcx = relation.tcx();
+
+ let a_ty;
+ let b_ty;
+ if relation.tcx().features().adt_const_params {
+ a_ty = tcx.normalize_erasing_regions(relation.param_env(), a.ty());
+ b_ty = tcx.normalize_erasing_regions(relation.param_env(), b.ty());
+ } else {
+ a_ty = tcx.erase_regions(a.ty());
+ b_ty = tcx.erase_regions(b.ty());
+ }
+ if a_ty != b_ty {
+ relation.tcx().sess.delay_span_bug(
+ DUMMY_SP,
+ &format!("cannot relate constants of different types: {} != {}", a_ty, b_ty),
+ );
+ }
+
+ let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env());
+ let a = eagerly_eval(a);
+ let b = eagerly_eval(b);
+
+ // Currently, the values that can be unified are primitive types,
+ // and those that derive both `PartialEq` and `Eq`, corresponding
+ // to structural-match types.
+ let is_match = match (a.kind(), b.kind()) {
+ (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
+ // The caller should handle these cases!
+ bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
+ }
+
+ (ty::ConstKind::Error(_), _) => return Ok(a),
+ (_, ty::ConstKind::Error(_)) => return Ok(b),
+
+ (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
+ (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
+ (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
+
+ (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
+ if tcx.features().generic_const_exprs =>
+ {
+ tcx.try_unify_abstract_consts(relation.param_env().and((au.shrink(), bu.shrink())))
+ }
+
+ // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
+ // and is the better alternative to waiting until `generic_const_exprs` can
+ // be stabilized.
+ (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
+ if au.def == bu.def && au.promoted == bu.promoted =>
+ {
+ let substs = relation.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ au.substs,
+ bu.substs,
+ )?;
+ return Ok(tcx.mk_const(ty::ConstS {
+ kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: au.def,
+ substs,
+ promoted: au.promoted,
+ }),
+ ty: a.ty(),
+ }));
+ }
+ _ => false,
+ };
+ if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) }
+}
+
+impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: Self,
+ b: Self,
+ ) -> RelateResult<'tcx, Self> {
+ let tcx = relation.tcx();
+
+ // FIXME: this is wasteful, but want to do a perf run to see how slow it is.
+ // We need to perform this deduplication as we sometimes generate duplicate projections
+ // in `a`.
+ let mut a_v: Vec<_> = a.into_iter().collect();
+ let mut b_v: Vec<_> = b.into_iter().collect();
+ // `skip_binder` here is okay because `stable_cmp` doesn't look at binders
+ a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
+ a_v.dedup();
+ b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
+ b_v.dedup();
+ if a_v.len() != b_v.len() {
+ return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
+ }
+
+ let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
+ use crate::ty::ExistentialPredicate::*;
+ match (ep_a.skip_binder(), ep_b.skip_binder()) {
+ (Trait(a), Trait(b)) => Ok(ep_a
+ .rebind(Trait(relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder()))),
+ (Projection(a), Projection(b)) => Ok(ep_a.rebind(Projection(
+ relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
+ ))),
+ (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))),
+ _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
+ }
+ });
+ tcx.mk_poly_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, 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, 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, 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 ty::Const<'tcx> {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::Const<'tcx>,
+ b: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+ relation.consts(a, b)
+ }
+}
+
+impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::Binder<'tcx, T>,
+ b: ty::Binder<'tcx, T>,
+ ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
+ relation.binders(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::ImplPolarity {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::ImplPolarity,
+ b: ty::ImplPolarity,
+ ) -> RelateResult<'tcx, ty::ImplPolarity> {
+ if a != b {
+ Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+}
+
+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)?,
+ constness: relation.relate(a.constness, b.constness)?,
+ polarity: relation.relate(a.polarity, b.polarity)?,
+ })
+ }
+}
+
+impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: Self,
+ b: Self,
+ ) -> RelateResult<'tcx, Self> {
+ Ok(match (a, b) {
+ (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
+ (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+ _ => return Err(TypeError::Mismatch),
+ })
+ }
+}
+
+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)?,
+ term: relation.relate(a.term, b.term)?,
+ })
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Error handling
+
+pub fn expected_found<'tcx, R, T>(relation: &mut R, a: T, b: T) -> ExpectedFound<T>
+where
+ R: TypeRelation<'tcx>,
+{
+ ExpectedFound::new(relation.a_is_expected(), a, b)
+}
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
new file mode 100644
index 000000000..e86dafae3
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -0,0 +1,57 @@
+use crate::middle::region::{Scope, ScopeData, ScopeTree};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+
+/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
+/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
+pub struct RvalueScopes {
+ map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
+}
+
+impl RvalueScopes {
+ pub fn new() -> Self {
+ Self { map: <_>::default() }
+ }
+
+ /// Returns the scope when the temp created by `expr_id` will be cleaned up.
+ pub fn temporary_scope(
+ &self,
+ region_scope_tree: &ScopeTree,
+ expr_id: hir::ItemLocalId,
+ ) -> Option<Scope> {
+ // Check for a designated rvalue scope.
+ if let Some(&s) = self.map.get(&expr_id) {
+ debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
+ 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, _)) = region_scope_tree.parent_map.get(&id) {
+ match p.data {
+ ScopeData::Destruction => {
+ debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
+ return Some(id);
+ }
+ _ => id = p,
+ }
+ }
+
+ debug!("temporary_scope({expr_id:?}) = None");
+ None
+ }
+
+ /// Make an association between a sub-expression and an extended lifetime
+ pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
+ debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
+ if let Some(lifetime) = lifetime {
+ assert!(var != lifetime.item_local_id());
+ }
+ self.map.insert(var, lifetime);
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
new file mode 100644
index 000000000..7660a2f3a
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -0,0 +1,1304 @@
+//! 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::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
+use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
+use rustc_data_structures::functor::IdFunctor;
+use rustc_hir as hir;
+use rustc_hir::def::Namespace;
+use rustc_index::vec::{Idx, IndexVec};
+
+use std::fmt;
+use std::mem::ManuallyDrop;
+use std::ops::ControlFlow;
+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| {
+ with_no_trimmed_paths!({
+ f.write_str(
+ &FmtPrinter::new(tcx, Namespace::TypeNS)
+ .print_def_path(self.def_id, &[])?
+ .into_buffer(),
+ )
+ })
+ })
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::AdtDef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ ty::tls::with(|tcx| {
+ with_no_trimmed_paths!({
+ f.write_str(
+ &FmtPrinter::new(tcx, Namespace::TypeNS)
+ .print_def_path(self.did(), &[])?
+ .into_buffer(),
+ )
+ })
+ })
+ }
+}
+
+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<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ with_no_trimmed_paths!(fmt::Display::fmt(self, f))
+ }
+}
+
+impl<'tcx> 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::BoundRegionKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
+ ty::BrNamed(did, name) => {
+ if did.is_crate_root() {
+ write!(f, "BrNamed({})", name)
+ } else {
+ write!(f, "BrNamed({:?}, {})", did, name)
+ }
+ }
+ ty::BrEnv => write!(f, "BrEnv"),
+ }
+ }
+}
+
+impl fmt::Debug for ty::FreeRegion {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region)
+ }
+}
+
+impl<'tcx> 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<'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::RegionVid {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "'_#{}r", self.index())
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ with_no_trimmed_paths!(fmt::Display::fmt(self, f))
+ }
+}
+
+impl<'tcx> fmt::Debug for Ty<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ with_no_trimmed_paths!(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<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let ty::BoundConstness::ConstIfConst = self.constness {
+ write!(f, "~const ")?;
+ }
+ write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.kind())
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ ty::PredicateKind::Trait(ref a) => a.fmt(f),
+ ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
+ ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
+ ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
+ ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
+ ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
+ ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data),
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ write!(f, "ObjectSafe({:?})", trait_def_id)
+ }
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
+ write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
+ }
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
+ }
+ ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+ write!(f, "TypeWellFormedFromEnv({:?})", ty)
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Atomic structs
+//
+// For things that don't carry any arena-allocated data (and are
+// copy...), just add them to this list.
+
+TrivialTypeTraversalAndLiftImpls! {
+ (),
+ bool,
+ usize,
+ ::rustc_target::abi::VariantIdx,
+ u32,
+ u64,
+ String,
+ crate::middle::region::Scope,
+ crate::ty::FloatTy,
+ ::rustc_ast::InlineAsmOptions,
+ ::rustc_ast::InlineAsmTemplatePiece,
+ ::rustc_ast::NodeId,
+ ::rustc_span::symbol::Symbol,
+ ::rustc_hir::def::Res,
+ ::rustc_hir::def_id::DefId,
+ ::rustc_hir::def_id::LocalDefId,
+ ::rustc_hir::HirId,
+ ::rustc_hir::MatchSource,
+ ::rustc_hir::Mutability,
+ ::rustc_hir::Unsafety,
+ ::rustc_target::asm::InlineAsmRegOrRegClass,
+ ::rustc_target::spec::abi::Abi,
+ crate::mir::coverage::ExpressionOperandId,
+ crate::mir::coverage::CounterValueReference,
+ crate::mir::coverage::InjectedExpressionId,
+ crate::mir::coverage::InjectedExpressionIndex,
+ crate::mir::coverage::MappedExpressionIndex,
+ crate::mir::Local,
+ crate::mir::Promoted,
+ crate::traits::Reveal,
+ crate::ty::adjustment::AutoBorrowMutability,
+ crate::ty::AdtKind,
+ crate::ty::BoundConstness,
+ // Including `BoundRegionKind` 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::BoundRegionKind,
+ crate::ty::AssocItem,
+ crate::ty::AssocKind,
+ crate::ty::Placeholder<crate::ty::BoundRegionKind>,
+ 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,
+ ::rustc_errors::ErrorGuaranteed,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// 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> {
+ Some((tcx.lift(self.0)?, tcx.lift(self.1)?))
+ }
+}
+
+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> {
+ Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?))
+ }
+}
+
+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(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(x) => tcx.lift(x).map(Ok),
+ Err(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> + Clone> Lift<'tcx> for Rc<T> {
+ type Lifted = Rc<T::Lifted>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(self.as_ref().clone()).map(Rc::new)
+ }
+}
+
+impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
+ type Lifted = Arc<T::Lifted>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(self.as_ref().clone()).map(Arc::new)
+ }
+}
+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> {
+ self.into_iter().map(|v| tcx.lift(v)).collect()
+ }
+}
+
+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.into_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 Term<'a> {
+ type Lifted = ty::Term<'tcx>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ Some(match self {
+ Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
+ Term::Const(c) => Term::Const(tcx.lift(c)?),
+ })
+ }
+}
+
+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,
+ constness: self.constness,
+ polarity: self.polarity,
+ })
+ }
+}
+
+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<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> {
+ type Lifted = ty::CoercePredicate<'tcx>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> {
+ tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { 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.term))
+ .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
+ }
+}
+
+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,
+ term: tcx.lift(self.term).expect("type must lift when substs do"),
+ item_def_id: self.item_def_id,
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
+ type Lifted = ty::PredicateKind<'tcx>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ match self {
+ ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait),
+ ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
+ ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce),
+ ty::PredicateKind::RegionOutlives(data) => {
+ tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
+ }
+ ty::PredicateKind::TypeOutlives(data) => {
+ tcx.lift(data).map(ty::PredicateKind::TypeOutlives)
+ }
+ ty::PredicateKind::Projection(data) => {
+ tcx.lift(data).map(ty::PredicateKind::Projection)
+ }
+ ty::PredicateKind::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateKind::WellFormed),
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
+ tcx.lift(closure_substs).map(|closure_substs| {
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind)
+ })
+ }
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ Some(ty::PredicateKind::ObjectSafe(trait_def_id))
+ }
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv))
+ }
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+ tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T>
+where
+ <T as Lift<'tcx>>::Lifted: TypeVisitable<'tcx>,
+{
+ type Lifted = ty::Binder<'tcx, T::Lifted>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ let bound_vars = tcx.lift(self.bound_vars());
+ tcx.lift(self.skip_binder())
+ .zip(bound_vars)
+ .map(|(value, vars)| ty::Binder::bind_with_vars(value, vars))
+ }
+}
+
+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::new(caller_bounds, self.reveal(), self.constness()))
+ }
+}
+
+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> {
+ let ty::adjustment::Adjustment { kind, target } = self;
+ tcx.lift(kind).and_then(|kind| {
+ tcx.lift(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(overloaded) => {
+ tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref)
+ }
+ ty::adjustment::Adjust::Borrow(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,
+ span: self.span,
+ })
+ }
+}
+
+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> {
+ let ty::error::ExpectedFound { expected, found } = self;
+ tcx.lift(expected).and_then(|expected| {
+ tcx.lift(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,
+ ConstnessMismatch(x) => ConstnessMismatch(x),
+ PolarityMismatch(x) => PolarityMismatch(x),
+ UnsafetyMismatch(x) => UnsafetyMismatch(x),
+ AbiMismatch(x) => AbiMismatch(x),
+ Mutability => Mutability,
+ ArgumentMutability(i) => ArgumentMutability(i),
+ TupleSize(x) => TupleSize(x),
+ FixedArraySize(x) => FixedArraySize(x),
+ ArgCount => ArgCount,
+ FieldMisMatch(x, y) => FieldMisMatch(x, y),
+ 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)),
+ CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)),
+ ProjectionMismatched(x) => ProjectionMismatched(x),
+ ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)),
+ Sorts(x) => return tcx.lift(x).map(Sorts),
+ ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
+ ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),
+ IntrinsicCast => IntrinsicCast,
+ TargetFeatureCast(x) => TargetFeatureCast(x),
+ ObjectUnsafeCoercion(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, 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, track_caller } => {
+ Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller })
+ }
+ ty::InstanceDef::DropGlue(def_id, ty) => {
+ Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?))
+ }
+ ty::InstanceDef::CloneShim(def_id, ty) => {
+ Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?))
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeFoldable implementations.
+
+/// AdtDefs are basically the same as a DefId.
+impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<(T, U), F::Error> {
+ Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>, U: TypeVisitable<'tcx>> TypeVisitable<'tcx> for (T, U) {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.0.visit_with(visitor)?;
+ self.1.visit_with(visitor)
+ }
+}
+
+impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
+ for (A, B, C)
+{
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<(A, B, C), F::Error> {
+ Ok((
+ self.0.try_fold_with(folder)?,
+ self.1.try_fold_with(folder)?,
+ self.2.try_fold_with(folder)?,
+ ))
+ }
+}
+
+impl<'tcx, A: TypeVisitable<'tcx>, B: TypeVisitable<'tcx>, C: TypeVisitable<'tcx>>
+ TypeVisitable<'tcx> for (A, B, C)
+{
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.0.visit_with(visitor)?;
+ self.1.visit_with(visitor)?;
+ self.2.visit_with(visitor)
+ }
+}
+
+EnumTypeTraversalImpl! {
+ impl<'tcx, T> TypeFoldable<'tcx> for Option<T> {
+ (Some)(a),
+ (None),
+ } where T: TypeFoldable<'tcx>
+}
+EnumTypeTraversalImpl! {
+ impl<'tcx, T> TypeVisitable<'tcx> for Option<T> {
+ (Some)(a),
+ (None),
+ } where T: TypeVisitable<'tcx>
+}
+
+EnumTypeTraversalImpl! {
+ impl<'tcx, T, E> TypeFoldable<'tcx> for Result<T, E> {
+ (Ok)(a),
+ (Err)(a),
+ } where T: TypeFoldable<'tcx>, E: TypeFoldable<'tcx>,
+}
+EnumTypeTraversalImpl! {
+ impl<'tcx, T, E> TypeVisitable<'tcx> for Result<T, E> {
+ (Ok)(a),
+ (Err)(a),
+ } where T: TypeVisitable<'tcx>, E: TypeVisitable<'tcx>,
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
+ mut self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ // We merely want to replace the contained `T`, if at all possible,
+ // so that we don't needlessly allocate a new `Rc` or indeed clone
+ // the contained type.
+ unsafe {
+ // First step is to ensure that we have a unique reference to
+ // the contained type, which `Rc::make_mut` will accomplish (by
+ // allocating a new `Rc` and cloning the `T` only if required).
+ // This is done *before* casting to `Rc<ManuallyDrop<T>>` so that
+ // panicking during `make_mut` does not leak the `T`.
+ Rc::make_mut(&mut self);
+
+ // Casting to `Rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+ // is `repr(transparent)`.
+ let ptr = Rc::into_raw(self).cast::<ManuallyDrop<T>>();
+ let mut unique = Rc::from_raw(ptr);
+
+ // Call to `Rc::make_mut` above guarantees that `unique` is the
+ // sole reference to the contained value, so we can avoid doing
+ // a checked `get_mut` here.
+ let slot = Rc::get_mut_unchecked(&mut unique);
+
+ // Semantically move the contained type out from `unique`, fold
+ // it, then move the folded value back into `unique`. Should
+ // folding fail, `ManuallyDrop` ensures that the "moved-out"
+ // value is not re-dropped.
+ let owned = ManuallyDrop::take(slot);
+ let folded = owned.try_fold_with(folder)?;
+ *slot = ManuallyDrop::new(folded);
+
+ // Cast back to `Rc<T>`.
+ Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
+ }
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Rc<T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ (**self).visit_with(visitor)
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
+ mut self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ // We merely want to replace the contained `T`, if at all possible,
+ // so that we don't needlessly allocate a new `Arc` or indeed clone
+ // the contained type.
+ unsafe {
+ // First step is to ensure that we have a unique reference to
+ // the contained type, which `Arc::make_mut` will accomplish (by
+ // allocating a new `Arc` and cloning the `T` only if required).
+ // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
+ // panicking during `make_mut` does not leak the `T`.
+ Arc::make_mut(&mut self);
+
+ // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+ // is `repr(transparent)`.
+ let ptr = Arc::into_raw(self).cast::<ManuallyDrop<T>>();
+ let mut unique = Arc::from_raw(ptr);
+
+ // Call to `Arc::make_mut` above guarantees that `unique` is the
+ // sole reference to the contained value, so we can avoid doing
+ // a checked `get_mut` here.
+ let slot = Arc::get_mut_unchecked(&mut unique);
+
+ // Semantically move the contained type out from `unique`, fold
+ // it, then move the folded value back into `unique`. Should
+ // folding fail, `ManuallyDrop` ensures that the "moved-out"
+ // value is not re-dropped.
+ let owned = ManuallyDrop::take(slot);
+ let folded = owned.try_fold_with(folder)?;
+ *slot = ManuallyDrop::new(folded);
+
+ // Cast back to `Arc<T>`.
+ Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
+ }
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Arc<T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ (**self).visit_with(visitor)
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.try_fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ (**self).visit_with(visitor)
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec<T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_bound(|ty| ty.try_fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::EarlyBinder<T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.as_ref().0.visit_with(visitor)
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_binder(self)
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::Binder<'tcx, T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_binder(self)
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<'tcx> for ty::Binder<'tcx, T> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_bound(|ty| ty.try_fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>> TypeSuperVisitable<'tcx> for ty::Binder<'tcx, T> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.as_ref().skip_binder().visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx>
+ for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
+{
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|p| p.visit_with(visitor))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ProjectionKind> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ use crate::ty::InstanceDef::*;
+ Ok(Self {
+ substs: self.substs.try_fold_with(folder)?,
+ def: match self.def {
+ Item(def) => Item(def.try_fold_with(folder)?),
+ VTableShim(did) => VTableShim(did.try_fold_with(folder)?),
+ ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?),
+ Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?),
+ FnPtrShim(did, ty) => {
+ FnPtrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ Virtual(did, i) => Virtual(did.try_fold_with(folder)?, i),
+ ClosureOnceShim { call_once, track_caller } => {
+ ClosureOnceShim { call_once: call_once.try_fold_with(folder)?, track_caller }
+ }
+ DropGlue(did, ty) => {
+ DropGlue(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ CloneShim(did, ty) => {
+ CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ },
+ })
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ use crate::ty::InstanceDef::*;
+ self.substs.visit_with(visitor)?;
+ match self.def {
+ Item(def) => def.visit_with(visitor),
+ 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, track_caller: _ } => call_once.visit_with(visitor),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted })
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for interpret::GlobalId<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.instance.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_ty(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Ty<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_ty(*self)
+ }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let kind = match *self.kind() {
+ ty::RawPtr(tm) => ty::RawPtr(tm.try_fold_with(folder)?),
+ ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?),
+ ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?),
+ ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?),
+ ty::Dynamic(trait_ty, region) => {
+ ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?)
+ }
+ ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
+ ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?),
+ ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?),
+ ty::Ref(r, ty, mutbl) => {
+ ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
+ }
+ ty::Generator(did, substs, movability) => {
+ ty::Generator(did, substs.try_fold_with(folder)?, movability)
+ }
+ ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?),
+ ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?),
+ ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?),
+ ty::Opaque(did, substs) => ty::Opaque(did, substs.try_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 Ok(self),
+ };
+
+ Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
+ }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ 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) => 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(..) => ControlFlow::CONTINUE,
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_region(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::Region<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_region(*self)
+ }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_predicate(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::Predicate<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_predicate(*self)
+ }
+
+ #[inline]
+ fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+ self.outer_exclusive_binder() > binder
+ }
+
+ #[inline]
+ fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
+ self.flags().intersects(flags)
+ }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Predicate<'tcx> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let new = self.kind().try_fold_with(folder)?;
+ Ok(folder.tcx().reuse_or_mk_predicate(self, new))
+ }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Predicate<'tcx> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.kind().visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|p| p.visit_with(visitor))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|x| x.try_fold_with(folder))
+ }
+}
+
+impl<'tcx, T: TypeVisitable<'tcx>, I: Idx> TypeVisitable<'tcx> for IndexVec<I, T> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_const(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::Const<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_const(*self)
+ }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Const<'tcx> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let ty = self.ty().try_fold_with(folder)?;
+ let kind = self.kind().try_fold_with(folder)?;
+ if ty != self.ty() || kind != self.kind() {
+ Ok(folder.tcx().mk_const(ty::ConstS { ty, kind }))
+ } else {
+ Ok(self)
+ }
+ }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.ty().visit_with(visitor)?;
+ self.kind().visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(match self {
+ ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?),
+ ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?),
+ ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?),
+ ty::ConstKind::Value(_)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Placeholder(..)
+ | ty::ConstKind::Error(_) => self,
+ })
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::ConstKind<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ match *self {
+ ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
+ ty::ConstKind::Param(p) => p.visit_with(visitor),
+ ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
+ ty::ConstKind::Value(_)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Error(_) => ControlFlow::CONTINUE,
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_unevaluated(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_unevaluated(*self)
+ }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Unevaluated<'tcx> {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
+ def: self.def,
+ substs: self.substs.try_fold_with(folder)?,
+ promoted: self.promoted,
+ })
+ }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Unevaluated<'tcx> {
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.substs.visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self.expand().try_fold_with(folder)?.shrink())
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.expand().visit_with(visitor)
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for hir::Constness {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
new file mode 100644
index 000000000..52c3a3886
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -0,0 +1,2295 @@
+//! This module contains `TyKind` and its major components.
+
+#![allow(rustc::usage_of_ty_tykind)]
+
+use crate::infer::canonical::Canonical;
+use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::visit::ValidateBoundVars;
+use crate::ty::InferTy::*;
+use crate::ty::{
+ self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
+ TypeVisitor,
+};
+use crate::ty::{List, ParamEnv};
+use polonius_engine::Atom;
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::intern::Interned;
+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::abi::VariantIdx;
+use rustc_target::spec::abi;
+use std::borrow::Cow;
+use std::cmp::Ordering;
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::{ControlFlow, Deref, Range};
+use ty::util::IntTypeExt;
+
+use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::RegionKind as IrRegionKind;
+use rustc_type_ir::TyKind as IrTyKind;
+
+// Re-export the `TyKind` from `rustc_type_ir` here for convenience
+#[rustc_diagnostic_item = "TyKind"]
+pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
+pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct TypeAndMut<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub mutbl: hir::Mutability,
+}
+
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
+#[derive(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: BoundRegionKind,
+}
+
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)]
+#[derive(HashStable)]
+pub enum BoundRegionKind {
+ /// 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,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)]
+#[derive(HashStable)]
+pub struct BoundRegion {
+ pub var: BoundVar,
+ pub kind: BoundRegionKind,
+}
+
+impl BoundRegionKind {
+ pub fn is_named(&self) -> bool {
+ match *self {
+ BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime,
+ _ => false,
+ }
+ }
+}
+
+pub trait Article {
+ fn article(&self) -> &'static str;
+}
+
+impl<'tcx> Article for TyKind<'tcx> {
+ /// Get the article ("a" or "an") to use with this type.
+ fn article(&self) -> &'static str {
+ match self {
+ Int(_) | Float(_) | Array(_, _) => "an",
+ Adt(def, _) if def.is_enum() => "an",
+ // This should never happen, but ICEing and causing the user's code
+ // to not compile felt too harsh.
+ Error(_) => "a",
+ _ => "a",
+ }
+ }
+}
+
+// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(TyKind<'_>, 32);
+
+/// A closure can be modeled as a struct that looks like:
+/// ```ignore (illustrative)
+/// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U);
+/// ```
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic 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
+/// `Ty::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.
+/// - U is a type parameter representing the types of its upvars, tupled up
+/// (borrowed, if appropriate; that is, if a U field represents a by-ref upvar,
+/// and the up-var has the type `Foo`, then that field of U will be `&Foo`).
+///
+/// So, for example, given this function:
+/// ```ignore (illustrative)
+/// fn foo<'a, T>(data: &'a mut T) {
+/// do(|| data.count += 1)
+/// }
+/// ```
+/// the type of the closure would be something like:
+/// ```ignore (illustrative)
+/// struct Closure<'a, T, U>(...U);
+/// ```
+/// 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:
+/// ```ignore (illustrative)
+/// 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
+/// in an extra type parameter? 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, TypeVisitable)]
+pub struct ClosureSubsts<'tcx> {
+ /// Lifetime and type parameters from the enclosing function,
+ /// concatenated with a tuple containing 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()`.
+pub struct ClosureSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub closure_kind_ty: T,
+ pub closure_sig_as_fn_ptr_ty: T,
+ pub tupled_upvars_ty: T,
+}
+
+impl<'tcx> ClosureSubsts<'tcx> {
+ /// Construct `ClosureSubsts` from `ClosureSubstsParts`, containing `Substs`
+ /// for the closure parent, alongside additional closure-specific components.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: ClosureSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> ClosureSubsts<'tcx> {
+ ClosureSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(
+ [parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty]
+ .iter()
+ .map(|&ty| ty.into()),
+ ),
+ ),
+ }
+ }
+
+ /// Divides the closure substs into their respective components.
+ /// The ordering assumed here must match that used by `ClosureSubsts::new` above.
+ fn split(self) -> ClosureSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [
+ ref parent_substs @ ..,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ ] => ClosureSubstsParts {
+ parent_substs,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ },
+ _ => bug!("closure substs missing synthetics"),
+ }
+ }
+
+ /// Returns `true` only if enough of the synthetic types are known to
+ /// allow using all of the methods on `ClosureSubsts` without panicking.
+ ///
+ /// Used primarily by `ty::print::pretty` to be able to handle closure
+ /// types that haven't had their synthetic types substituted in.
+ pub fn is_valid(self) -> bool {
+ self.substs.len() >= 3
+ && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_))
+ }
+
+ /// Returns the substitutions of the closure's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// Returns an iterator over the list of types of captured paths by the closure.
+ /// In case there was a type error in figuring out the types of the captured path, an
+ /// empty iterator is returned.
+ #[inline]
+ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+ match self.tupled_upvars_ty().kind() {
+ TyKind::Error(_) => None,
+ TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
+ TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
+ ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
+ }
+ .into_iter()
+ .flatten()
+ }
+
+ /// Returns the tuple type representing the upvars for this closure.
+ #[inline]
+ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+ self.split().tupled_upvars_ty.expect_ty()
+ }
+
+ /// 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(substs)`.
+ pub fn kind_ty(self) -> Ty<'tcx> {
+ self.split().closure_kind_ty.expect_ty()
+ }
+
+ /// Returns the `fn` pointer type representing the closure signature for this
+ /// closure.
+ // FIXME(eddyb) this should be unnecessary, as the shallowly resolved
+ // type is known at the time of the creation of `ClosureSubsts`,
+ // see `rustc_typeck::check::closure`.
+ pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> {
+ self.split().closure_sig_as_fn_ptr_ty.expect_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) -> ty::ClosureKind {
+ self.kind_ty().to_opt_closure_kind().unwrap()
+ }
+
+ /// Extracts the signature from the closure.
+ pub fn sig(self) -> ty::PolyFnSig<'tcx> {
+ let ty = self.sig_as_fn_ptr_ty();
+ match ty.kind() {
+ ty::FnPtr(sig) => *sig,
+ _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()),
+ }
+ }
+}
+
+/// Similar to `ClosureSubsts`; see the above documentation for more.
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+pub struct GeneratorSubsts<'tcx> {
+ pub substs: SubstsRef<'tcx>,
+}
+
+pub struct GeneratorSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub resume_ty: T,
+ pub yield_ty: T,
+ pub return_ty: T,
+ pub witness: T,
+ pub tupled_upvars_ty: T,
+}
+
+impl<'tcx> GeneratorSubsts<'tcx> {
+ /// Construct `GeneratorSubsts` from `GeneratorSubstsParts`, containing `Substs`
+ /// for the generator parent, alongside additional generator-specific components.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: GeneratorSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> GeneratorSubsts<'tcx> {
+ GeneratorSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(
+ [
+ parts.resume_ty,
+ parts.yield_ty,
+ parts.return_ty,
+ parts.witness,
+ parts.tupled_upvars_ty,
+ ]
+ .iter()
+ .map(|&ty| ty.into()),
+ ),
+ ),
+ }
+ }
+
+ /// Divides the generator substs into their respective components.
+ /// The ordering assumed here must match that used by `GeneratorSubsts::new` above.
+ fn split(self) -> GeneratorSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [ref parent_substs @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
+ GeneratorSubstsParts {
+ parent_substs,
+ resume_ty,
+ yield_ty,
+ return_ty,
+ witness,
+ tupled_upvars_ty,
+ }
+ }
+ _ => bug!("generator substs missing synthetics"),
+ }
+ }
+
+ /// Returns `true` only if enough of the synthetic types are known to
+ /// allow using all of the methods on `GeneratorSubsts` without panicking.
+ ///
+ /// Used primarily by `ty::print::pretty` to be able to handle generator
+ /// types that haven't had their synthetic types substituted in.
+ pub fn is_valid(self) -> bool {
+ self.substs.len() >= 5
+ && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_))
+ }
+
+ /// Returns the substitutions of the generator's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// 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) -> Ty<'tcx> {
+ self.split().witness.expect_ty()
+ }
+
+ /// Returns an iterator over the list of types of captured paths by the generator.
+ /// In case there was a type error in figuring out the types of the captured path, an
+ /// empty iterator is returned.
+ #[inline]
+ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+ match self.tupled_upvars_ty().kind() {
+ TyKind::Error(_) => None,
+ TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
+ TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
+ ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
+ }
+ .into_iter()
+ .flatten()
+ }
+
+ /// Returns the tuple type representing the upvars for this generator.
+ #[inline]
+ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+ self.split().tupled_upvars_ty.expect_ty()
+ }
+
+ /// Returns the type representing the resume type of the generator.
+ pub fn resume_ty(self) -> Ty<'tcx> {
+ self.split().resume_ty.expect_ty()
+ }
+
+ /// Returns the type representing the yield type of the generator.
+ pub fn yield_ty(self) -> Ty<'tcx> {
+ self.split().yield_ty.expect_ty()
+ }
+
+ /// Returns the type representing the return type of the generator.
+ pub fn return_ty(self) -> Ty<'tcx> {
+ self.split().return_ty.expect_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) -> PolyGenSig<'tcx> {
+ ty::Binder::dummy(self.sig())
+ }
+
+ /// Returns the "generator signature", which consists of its resume, yield
+ /// and return types.
+ pub fn sig(self) -> GenSig<'tcx> {
+ ty::GenSig {
+ resume_ty: self.resume_ty(),
+ yield_ty: self.yield_ty(),
+ return_ty: self.return_ty(),
+ }
+ }
+}
+
+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).unwrap().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`.
+ pub fn variant_name(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).unwrap();
+ layout.variant_fields.iter().map(move |variant| {
+ variant
+ .iter()
+ .map(move |field| EarlyBinder(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) -> impl Iterator<Item = Ty<'tcx>> {
+ self.upvar_tys()
+ }
+}
+
+#[derive(Debug, Copy, Clone, HashStable)]
+pub enum UpvarSubsts<'tcx> {
+ Closure(SubstsRef<'tcx>),
+ Generator(SubstsRef<'tcx>),
+}
+
+impl<'tcx> UpvarSubsts<'tcx> {
+ /// Returns an iterator over the list of types of captured paths by the closure/generator.
+ /// In case there was a type error in figuring out the types of the captured path, an
+ /// empty iterator is returned.
+ #[inline]
+ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
+ let tupled_tys = match self {
+ UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
+ UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
+ };
+
+ match tupled_tys.kind() {
+ TyKind::Error(_) => None,
+ TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
+ TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
+ ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
+ }
+ .into_iter()
+ .flatten()
+ }
+
+ #[inline]
+ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+ match self {
+ UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
+ UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
+ }
+ }
+}
+
+/// An inline const is modeled like
+/// ```ignore (illustrative)
+/// const InlineConst<'l0...'li, T0...Tj, R>: R;
+/// ```
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+/// inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+pub struct InlineConstSubsts<'tcx> {
+ /// Generic parameters from the enclosing item,
+ /// concatenated with the inferred type of the constant.
+ pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+ /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+ ),
+ }
+ }
+
+ /// Divides the inline const substs into their respective components.
+ /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+ fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+ _ => bug!("inline const substs missing synthetics"),
+ }
+ }
+
+ /// Returns the substitutions of the inline const's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// Returns the type of this inline const.
+ pub fn ty(self) -> Ty<'tcx> {
+ self.split().ty.expect_ty()
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+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.def_path_hash(*a).cmp(&tcx.def_path_hash(*b))
+ }
+ (Trait(_), _) => Ordering::Less,
+ (Projection(_), Trait(_)) => Ordering::Greater,
+ (Projection(_), _) => Ordering::Less,
+ (AutoTrait(_), _) => Ordering::Greater,
+ }
+ }
+}
+
+impl<'tcx> Binder<'tcx, 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) => {
+ self.rebind(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
+ }
+ ExistentialPredicate::Projection(p) => {
+ self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
+ }
+ ExistentialPredicate::AutoTrait(did) => {
+ let trait_ref = self.rebind(ty::TraitRef {
+ def_id: did,
+ substs: tcx.mk_substs_trait(self_ty, &[]),
+ });
+ trait_ref.without_const().to_predicate(tcx)
+ }
+ }
+ }
+}
+
+impl<'tcx> List<ty::Binder<'tcx, 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<ty::Binder<'tcx, ExistentialTraitRef<'tcx>>> {
+ self[0]
+ .map_bound(|this| match this {
+ ExistentialPredicate::Trait(tr) => Some(tr),
+ _ => None,
+ })
+ .transpose()
+ }
+
+ pub fn principal_def_id(&self) -> Option<DefId> {
+ self.principal().map(|trait_ref| trait_ref.skip_binder().def_id)
+ }
+
+ #[inline]
+ pub fn projection_bounds<'a>(
+ &'a self,
+ ) -> impl Iterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> + 'a {
+ self.iter().filter_map(|predicate| {
+ predicate
+ .map_bound(|pred| match pred {
+ ExistentialPredicate::Projection(projection) => Some(projection),
+ _ => None,
+ })
+ .transpose()
+ })
+ }
+
+ #[inline]
+ pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + Captures<'tcx> + 'a {
+ self.iter().filter_map(|predicate| match predicate.skip_binder() {
+ ExistentialPredicate::AutoTrait(did) => Some(did),
+ _ => None,
+ })
+ }
+}
+
+/// A complete reference to a trait. These take numerous guises in syntax,
+/// but perhaps the most recognizable form is in a where-clause:
+/// ```ignore (illustrative)
+/// 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.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+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) -> Binder<'tcx, TraitRef<'tcx>> {
+ ty::Binder::dummy(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 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<'tcx, TraitRef<'tcx>>;
+
+impl<'tcx> PolyTraitRef<'tcx> {
+ pub fn self_ty(&self) -> Binder<'tcx, Ty<'tcx>> {
+ self.map_bound_ref(|tr| tr.self_ty())
+ }
+
+ pub fn def_id(&self) -> DefId {
+ self.skip_binder().def_id
+ }
+
+ pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
+ self.map_bound(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ }
+
+ /// Same as [`PolyTraitRef::to_poly_trait_predicate`] but sets a negative polarity instead.
+ pub fn to_poly_trait_predicate_negative_polarity(&self) -> ty::PolyTraitPredicate<'tcx> {
+ self.map_bound(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Negative,
+ })
+ }
+}
+
+/// An existential reference to a trait, where `Self` is erased.
+/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
+/// ```ignore (illustrative)
+/// 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct ExistentialTraitRef<'tcx> {
+ pub def_id: DefId,
+ pub substs: SubstsRef<'tcx>,
+}
+
+impl<'tcx> ExistentialTraitRef<'tcx> {
+ 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<'tcx, 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))
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable)]
+pub struct EarlyBinder<T>(pub T);
+
+impl<T> EarlyBinder<T> {
+ pub fn as_ref(&self) -> EarlyBinder<&T> {
+ EarlyBinder(&self.0)
+ }
+
+ pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
+ where
+ F: FnOnce(&T) -> U,
+ {
+ self.as_ref().map_bound(f)
+ }
+
+ pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ let value = f(self.0);
+ EarlyBinder(value)
+ }
+
+ pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
+ where
+ F: FnOnce(T) -> Result<U, E>,
+ {
+ let value = f(self.0)?;
+ Ok(EarlyBinder(value))
+ }
+
+ pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
+ EarlyBinder(value)
+ }
+}
+
+impl<T> EarlyBinder<Option<T>> {
+ pub fn transpose(self) -> Option<EarlyBinder<T>> {
+ self.0.map(|v| EarlyBinder(v))
+ }
+}
+
+impl<T, U> EarlyBinder<(T, U)> {
+ pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) {
+ (EarlyBinder(self.0.0), EarlyBinder(self.0.1))
+ }
+}
+
+pub struct EarlyBinderIter<T> {
+ t: T,
+}
+
+impl<T: IntoIterator> EarlyBinder<T> {
+ pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
+ EarlyBinderIter { t: self.0.into_iter() }
+ }
+}
+
+impl<T: Iterator> Iterator for EarlyBinderIter<T> {
+ type Item = EarlyBinder<T::Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.t.next().map(|i| EarlyBinder(i))
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable)]
+pub enum BoundVariableKind {
+ Ty(BoundTyKind),
+ Region(BoundRegionKind),
+ Const,
+}
+
+impl BoundVariableKind {
+ pub fn expect_region(self) -> BoundRegionKind {
+ match self {
+ BoundVariableKind::Region(lt) => lt,
+ _ => bug!("expected a region, but found another kind"),
+ }
+ }
+
+ pub fn expect_ty(self) -> BoundTyKind {
+ match self {
+ BoundVariableKind::Ty(ty) => ty,
+ _ => bug!("expected a type, but found another kind"),
+ }
+ }
+
+ pub fn expect_const(self) {
+ match self {
+ BoundVariableKind::Const => (),
+ _ => bug!("expected a const, but found another kind"),
+ }
+ }
+}
+
+/// 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<'tcx, TraitRef>`). Note that when we instantiate,
+/// erase, or otherwise "discharge" these bound vars, we change the
+/// type from `Binder<'tcx, T>` to just `T` (see
+/// e.g., `liberate_late_bound_regions`).
+///
+/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(HashStable)]
+pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>);
+
+impl<'tcx, T> Binder<'tcx, T>
+where
+ T: TypeVisitable<'tcx>,
+{
+ /// 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(value: T) -> Binder<'tcx, T> {
+ assert!(!value.has_escaping_bound_vars());
+ Binder(value, ty::List::empty())
+ }
+
+ pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(vars);
+ value.visit_with(&mut validator);
+ }
+ Binder(value, vars)
+ }
+}
+
+impl<'tcx, T> Binder<'tcx, T> {
+ /// 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 bound_vars(&self) -> &'tcx List<BoundVariableKind> {
+ self.1
+ }
+
+ pub fn as_ref(&self) -> Binder<'tcx, &T> {
+ Binder(&self.0, self.1)
+ }
+
+ pub fn as_deref(&self) -> Binder<'tcx, &T::Target>
+ where
+ T: Deref,
+ {
+ Binder(&self.0, self.1)
+ }
+
+ pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
+ where
+ F: FnOnce(&T) -> U,
+ {
+ let value = f(&self.0);
+ Binder(value, self.1)
+ }
+
+ pub fn map_bound_ref<F, U: TypeVisitable<'tcx>>(&self, f: F) -> Binder<'tcx, U>
+ where
+ F: FnOnce(&T) -> U,
+ {
+ self.as_ref().map_bound(f)
+ }
+
+ pub fn map_bound<F, U: TypeVisitable<'tcx>>(self, f: F) -> Binder<'tcx, U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ let value = f(self.0);
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.1);
+ value.visit_with(&mut validator);
+ }
+ Binder(value, self.1)
+ }
+
+ pub fn try_map_bound<F, U: TypeVisitable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
+ where
+ F: FnOnce(T) -> Result<U, E>,
+ {
+ let value = f(self.0)?;
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.1);
+ value.visit_with(&mut validator);
+ }
+ Ok(Binder(value, self.1))
+ }
+
+ /// Wraps a `value` in a binder, using the same bound variables as the
+ /// current `Binder`. This should not be used if the new value *changes*
+ /// the bound variables. Note: the (old or new) value itself does not
+ /// necessarily need to *name* all the bound variables.
+ ///
+ /// This currently doesn't do anything different than `bind`, because we
+ /// don't actually track bound vars. However, semantically, it is different
+ /// because bound vars aren't allowed to change here, whereas they are
+ /// in `bind`. This may be (debug) asserted in the future.
+ pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U>
+ where
+ U: TypeVisitable<'tcx>,
+ {
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.bound_vars());
+ value.visit_with(&mut validator);
+ }
+ Binder(value, self.1)
+ }
+
+ /// 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(self) -> Option<T>
+ where
+ T: TypeVisitable<'tcx>,
+ {
+ if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
+ }
+
+ /// 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<'tcx, U>, Binder<'tcx, V>)
+ where
+ F: FnOnce(T) -> (U, V),
+ {
+ let (u, v) = f(self.0);
+ (Binder(u, self.1), Binder(v, self.1))
+ }
+}
+
+impl<'tcx, T> Binder<'tcx, Option<T>> {
+ pub fn transpose(self) -> Option<Binder<'tcx, T>> {
+ let bound_vars = self.1;
+ self.0.map(|v| Binder(v, bound_vars))
+ }
+}
+
+/// 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+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`,
+ /// aka. `tcx.parent(item_def_id).unwrap()`.
+ pub item_def_id: DefId,
+}
+
+impl<'tcx> ProjectionTy<'tcx> {
+ pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+ tcx.parent(self.item_def_id)
+ }
+
+ /// Extracts the underlying trait reference and own substs from this projection.
+ /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+ /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+ pub fn trait_ref_and_own_substs(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
+ let def_id = tcx.parent(self.item_def_id);
+ let trait_generics = tcx.generics_of(def_id);
+ (
+ ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+ &self.substs[trait_generics.count()..],
+ )
+ }
+
+ /// 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.
+ ///
+ /// WARNING: This will drop the substs for generic associated types
+ /// consider calling [Self::trait_ref_and_own_substs] to get those
+ /// as well.
+ pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
+ let def_id = self.trait_def_id(tcx);
+ 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(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+pub struct GenSig<'tcx> {
+ pub resume_ty: Ty<'tcx>,
+ pub yield_ty: Ty<'tcx>,
+ pub return_ty: Ty<'tcx>,
+}
+
+pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>;
+
+/// 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+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<'tcx, FnSig<'tcx>>;
+
+impl<'tcx> PolyFnSig<'tcx> {
+ #[inline]
+ pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
+ self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs())
+ }
+ #[inline]
+ pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {
+ self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
+ }
+ pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> {
+ self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
+ }
+ #[inline]
+ pub fn output(&self) -> ty::Binder<'tcx, 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<'tcx, FnSig<'tcx>>>;
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable)]
+pub struct ParamTy {
+ pub index: u32,
+ pub name: Symbol,
+}
+
+impl<'tcx> ParamTy {
+ pub fn new(index: u32, name: Symbol) -> ParamTy {
+ ParamTy { index, name }
+ }
+
+ pub fn for_def(def: &ty::GenericParamDef) -> ParamTy {
+ ParamTy::new(def.index, def.name)
+ }
+
+ #[inline]
+ pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ tcx.mk_ty_param(self.index, self.name)
+ }
+}
+
+#[derive(Copy, Clone, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(HashStable)]
+pub struct ParamConst {
+ pub index: u32,
+ pub name: Symbol,
+}
+
+impl 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)
+ }
+}
+
+/// Use this rather than `RegionKind`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[rustc_pass_by_value]
+pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
+
+impl<'tcx> Deref for Region<'tcx> {
+ type Target = RegionKind<'tcx>;
+
+ #[inline]
+ fn deref(&self) -> &RegionKind<'tcx> {
+ &self.0.0
+ }
+}
+
+impl<'tcx> fmt::Debug for Region<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.kind())
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
+#[derive(HashStable)]
+pub struct EarlyBoundRegion {
+ pub def_id: DefId,
+ pub index: u32,
+ pub name: Symbol,
+}
+
+impl fmt::Debug for EarlyBoundRegion {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}, {}", self.index, self.name)
+ }
+}
+
+/// A **`const`** **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(HashStable, TyEncodable, TyDecodable)]
+pub struct ConstVid<'tcx> {
+ pub index: u32,
+ pub phantom: PhantomData<&'tcx ()>,
+}
+
+rustc_index::newtype_index! {
+ /// A **region** (lifetime) **v**ariable **ID**.
+ #[derive(HashStable)]
+ pub struct RegionVid {
+ DEBUG_FORMAT = custom,
+ }
+}
+
+impl Atom for RegionVid {
+ fn index(self) -> usize {
+ Idx::index(self)
+ }
+}
+
+rustc_index::newtype_index! {
+ #[derive(HashStable)]
+ pub struct BoundVar { .. }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable)]
+pub struct BoundTy {
+ pub var: BoundVar,
+ pub kind: BoundTyKind,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub struct ExistentialProjection<'tcx> {
+ pub item_def_id: DefId,
+ pub substs: SubstsRef<'tcx>,
+ pub term: Term<'tcx>,
+}
+
+pub type PolyExistentialProjection<'tcx> = Binder<'tcx, 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 an `exists T. T: Iterator` existential trait
+ /// reference.
+ pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
+ let def_id = tcx.parent(self.item_def_id);
+ let subst_count = tcx.generics_of(def_id).count() - 1;
+ let substs = tcx.intern_substs(&self.substs[..subst_count]);
+ ty::ExistentialTraitRef { def_id, 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),
+ },
+ term: self.term,
+ }
+ }
+
+ pub fn erase_self_ty(
+ tcx: TyCtxt<'tcx>,
+ projection_predicate: ty::ProjectionPredicate<'tcx>,
+ ) -> Self {
+ // Assert there is a Self.
+ projection_predicate.projection_ty.substs.type_at(0);
+
+ Self {
+ item_def_id: projection_predicate.projection_ty.item_def_id,
+ substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
+ term: projection_predicate.term,
+ }
+ }
+}
+
+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 {
+ self.skip_binder().item_def_id
+ }
+}
+
+/// Region utilities
+impl<'tcx> Region<'tcx> {
+ pub fn kind(self) -> RegionKind<'tcx> {
+ *self.0.0
+ }
+
+ /// Is this region named by the user?
+ pub fn has_name(self) -> bool {
+ match *self {
+ ty::ReEarlyBound(ebr) => ebr.has_name(),
+ ty::ReLateBound(_, br) => br.kind.is_named(),
+ ty::ReFree(fr) => fr.bound_region.is_named(),
+ ty::ReStatic => true,
+ ty::ReVar(..) => false,
+ ty::RePlaceholder(placeholder) => placeholder.name.is_named(),
+ ty::ReEmpty(_) => false,
+ ty::ReErased => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_static(self) -> bool {
+ matches!(*self, ty::ReStatic)
+ }
+
+ #[inline]
+ pub fn is_erased(self) -> bool {
+ matches!(*self, ty::ReErased)
+ }
+
+ #[inline]
+ pub fn is_late_bound(self) -> bool {
+ matches!(*self, ty::ReLateBound(..))
+ }
+
+ #[inline]
+ pub fn is_placeholder(self) -> bool {
+ matches!(*self, ty::RePlaceholder(..))
+ }
+
+ #[inline]
+ pub fn is_empty(self) -> bool {
+ matches!(*self, ty::ReEmpty(..))
+ }
+
+ #[inline]
+ pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
+ match *self {
+ ty::ReLateBound(debruijn, _) => debruijn >= index,
+ _ => false,
+ }
+ }
+
+ pub fn type_flags(self) -> TypeFlags {
+ let mut flags = TypeFlags::empty();
+
+ match *self {
+ ty::ReVar(..) => {
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_RE_INFER;
+ }
+ ty::RePlaceholder(..) => {
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
+ }
+ ty::ReEarlyBound(..) => {
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_RE_PARAM;
+ }
+ ty::ReFree { .. } => {
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ }
+ ty::ReEmpty(_) | ty::ReStatic => {
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ }
+ ty::ReLateBound(..) => {
+ flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
+ }
+ ty::ReErased => {
+ flags = flags | TypeFlags::HAS_RE_ERASED;
+ }
+ }
+
+ 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:
+ ///
+ /// ```ignore (illustrative)
+ /// 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),
+ ty::ReFree(fr) => fr.scope,
+ _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
+ }
+ }
+
+ /// True for free regions other than `'static`.
+ pub fn is_free(self) -> bool {
+ matches!(*self, ty::ReEarlyBound(_) | ty::ReFree(_))
+ }
+
+ /// True if `self` is a free region or static.
+ pub fn is_free_or_static(self) -> bool {
+ match *self {
+ ty::ReStatic => true,
+ _ => self.is_free(),
+ }
+ }
+}
+
+/// Type utilities
+impl<'tcx> Ty<'tcx> {
+ #[inline(always)]
+ pub fn kind(self) -> &'tcx TyKind<'tcx> {
+ &self.0.0.kind
+ }
+
+ #[inline(always)]
+ pub fn flags(self) -> TypeFlags {
+ self.0.0.flags
+ }
+
+ #[inline]
+ pub fn is_unit(self) -> bool {
+ match self.kind() {
+ Tuple(ref tys) => tys.is_empty(),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_never(self) -> bool {
+ matches!(self.kind(), Never)
+ }
+
+ #[inline]
+ pub fn is_primitive(self) -> bool {
+ self.kind().is_primitive()
+ }
+
+ #[inline]
+ pub fn is_adt(self) -> bool {
+ matches!(self.kind(), Adt(..))
+ }
+
+ #[inline]
+ pub fn is_ref(self) -> bool {
+ matches!(self.kind(), Ref(..))
+ }
+
+ #[inline]
+ pub fn is_ty_var(self) -> bool {
+ matches!(self.kind(), Infer(TyVar(_)))
+ }
+
+ #[inline]
+ pub fn ty_vid(self) -> Option<ty::TyVid> {
+ match self.kind() {
+ &Infer(TyVar(vid)) => Some(vid),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn is_ty_infer(self) -> bool {
+ matches!(self.kind(), Infer(_))
+ }
+
+ #[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 {
+ matches!(self.kind(), Slice(_))
+ }
+
+ #[inline]
+ pub fn is_array_slice(self) -> bool {
+ match self.kind() {
+ Slice(_) => true,
+ RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_array(self) -> bool {
+ matches!(self.kind(), Array(..))
+ }
+
+ #[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.types.u8,
+ _ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
+ }
+ }
+
+ pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
+ match self.kind() {
+ Adt(def, substs) => {
+ assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
+ let variant = def.non_enum_variant();
+ let f0_ty = variant.fields[0].ty(tcx, substs);
+
+ match f0_ty.kind() {
+ // If the first field is an array, we assume it is the only field and its
+ // elements are the SIMD components.
+ Array(f0_elem_ty, f0_len) => {
+ // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
+ // The way we evaluate the `N` in `[T; N]` here only works since we use
+ // `simd_size_and_type` post-monomorphization. It will probably start to ICE
+ // if we use it in generic code. See the `simd-array-trait` ui test.
+ (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty)
+ }
+ // Otherwise, the fields of this Adt are the SIMD components (and we assume they
+ // all have the same type).
+ _ => (variant.fields.len() as u64, f0_ty),
+ }
+ }
+ _ => bug!("`simd_size_and_type` called on invalid type"),
+ }
+ }
+
+ #[inline]
+ pub fn is_region_ptr(self) -> bool {
+ matches!(self.kind(), Ref(..))
+ }
+
+ #[inline]
+ pub fn is_mutable_ptr(self) -> bool {
+ matches!(
+ self.kind(),
+ RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
+ | Ref(_, _, hir::Mutability::Mut)
+ )
+ }
+
+ /// Get the mutability of the reference or `None` when not a reference
+ #[inline]
+ pub fn ref_mutability(self) -> Option<hir::Mutability> {
+ match self.kind() {
+ Ref(_, _, mutability) => Some(*mutability),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn is_unsafe_ptr(self) -> bool {
+ matches!(self.kind(), RawPtr(_))
+ }
+
+ /// 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()
+ }
+
+ #[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 {
+ matches!(
+ self.kind(),
+ Bool | Char
+ | Int(_)
+ | Float(_)
+ | Uint(_)
+ | FnDef(..)
+ | FnPtr(_)
+ | RawPtr(_)
+ | Infer(IntVar(_) | FloatVar(_))
+ )
+ }
+
+ /// Returns `true` if this type is a floating point type.
+ #[inline]
+ pub fn is_floating_point(self) -> bool {
+ matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
+ }
+
+ #[inline]
+ pub fn is_trait(self) -> bool {
+ matches!(self.kind(), Dynamic(..))
+ }
+
+ #[inline]
+ pub fn is_enum(self) -> bool {
+ matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
+ }
+
+ #[inline]
+ pub fn is_union(self) -> bool {
+ matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
+ }
+
+ #[inline]
+ pub fn is_closure(self) -> bool {
+ matches!(self.kind(), Closure(..))
+ }
+
+ #[inline]
+ pub fn is_generator(self) -> bool {
+ matches!(self.kind(), Generator(..))
+ }
+
+ #[inline]
+ pub fn is_integral(self) -> bool {
+ matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
+ }
+
+ #[inline]
+ pub fn is_fresh_ty(self) -> bool {
+ matches!(self.kind(), Infer(FreshTy(_)))
+ }
+
+ #[inline]
+ pub fn is_fresh(self) -> bool {
+ matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
+ }
+
+ #[inline]
+ pub fn is_char(self) -> bool {
+ matches!(self.kind(), Char)
+ }
+
+ #[inline]
+ pub fn is_numeric(self) -> bool {
+ self.is_integral() || self.is_floating_point()
+ }
+
+ #[inline]
+ pub fn is_signed(self) -> bool {
+ matches!(self.kind(), Int(_))
+ }
+
+ #[inline]
+ pub fn is_ptr_sized_integral(self) -> bool {
+ matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
+ }
+
+ #[inline]
+ pub fn has_concrete_skeleton(self) -> bool {
+ !matches!(self.kind(), Param(_) | Infer(_) | Error(_))
+ }
+
+ /// Checks whether a type recursively contains another type
+ ///
+ /// Example: `Option<()>` contains `()`
+ pub fn contains(self, other: Ty<'tcx>) -> bool {
+ struct ContainsTyVisitor<'tcx>(Ty<'tcx>);
+
+ impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) }
+ }
+ }
+
+ let cf = self.visit_with(&mut ContainsTyVisitor(other));
+ cf.is_break()
+ }
+
+ /// 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: *ty, mutbl: *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.bound_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 `substs.as_closure().sig()` not `fn_sig()`",
+ ),
+ _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self),
+ }
+ }
+
+ #[inline]
+ pub fn is_fn(self) -> bool {
+ matches!(self.kind(), FnDef(..) | FnPtr(_))
+ }
+
+ #[inline]
+ pub fn is_fn_ptr(self) -> bool {
+ matches!(self.kind(), FnPtr(_))
+ }
+
+ #[inline]
+ pub fn is_impl_trait(self) -> bool {
+ matches!(self.kind(), Opaque(..))
+ }
+
+ #[inline]
+ pub fn ty_adt_def(self) -> Option<AdtDef<'tcx>> {
+ match self.kind() {
+ Adt(adt, _) => Some(*adt),
+ _ => None,
+ }
+ }
+
+ /// Iterates over tuple fields.
+ /// Panics when called on anything but a tuple.
+ #[inline]
+ pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
+ match self.kind() {
+ Tuple(substs) => substs,
+ _ => 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, _) if adt.variants().is_empty() => {
+ // This can actually happen during CTFE, see
+ // https://github.com/rust-lang/rust/issues/89765.
+ None
+ }
+ TyKind::Adt(adt, _) if adt.is_enum() => {
+ 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,
+ }
+ }
+
+ /// Returns the type of the discriminant of this type.
+ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+ match self.kind() {
+ ty::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(tcx),
+ ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
+
+ ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => {
+ let assoc_items = tcx.associated_item_def_ids(
+ tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
+ );
+ tcx.mk_projection(assoc_items[0], tcx.intern_substs(&[self.into()]))
+ }
+
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(..)
+ | ty::Foreign(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ | ty::Tuple(_)
+ | ty::Error(_)
+ | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8,
+
+ ty::Bound(..)
+ | ty::Placeholder(_)
+ | ty::Infer(FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("`discriminant_ty` applied to unexpected type: {:?}", self)
+ }
+ }
+ }
+
+ /// Returns the type of metadata for (potentially fat) pointers to this type,
+ /// and a boolean signifying if this is conditional on this type being `Sized`.
+ pub fn ptr_metadata_ty(
+ self,
+ tcx: TyCtxt<'tcx>,
+ normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ ) -> (Ty<'tcx>, bool) {
+ let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
+ match tail.kind() {
+ // Sized types
+ ty::Infer(ty::IntVar(_) | 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(_)
+ // Extern types have metadata = ().
+ | ty::Foreign(..)
+ // If returned by `struct_tail_without_normalization` this is a unit struct
+ // without any fields, or not a struct, and therefore is Sized.
+ | ty::Adt(..)
+ // If returned by `struct_tail_without_normalization` this is the empty tuple,
+ // a.k.a. unit type, which is Sized
+ | ty::Tuple(..) => (tcx.types.unit, false),
+
+ ty::Str | ty::Slice(_) => (tcx.types.usize, false),
+ ty::Dynamic(..) => {
+ let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
+ (tcx.bound_type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
+ },
+
+ // type parameters only have unit metadata if they're sized, so return true
+ // to make sure we double check this during confirmation
+ ty::Param(_) | ty::Projection(_) | ty::Opaque(..) => (tcx.types.unit, true),
+
+ ty::Infer(ty::TyVar(_))
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
+ }
+ }
+ }
+
+ /// 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 `rustc_typeck/src/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 {
+ ty::IntTy::I8 => Some(ty::ClosureKind::Fn),
+ ty::IntTy::I16 => Some(ty::ClosureKind::FnMut),
+ ty::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.
+ ///
+ /// Note that we could never rely on the fact that a type such as `[_]` is
+ /// trivially `!Sized` because we could be in a type environment with a
+ /// bound such as `[_]: Copy`. A function with such a bound obviously never
+ /// can be called, but that doesn't mean it shouldn't typecheck. This is why
+ /// this method doesn't return `Option<bool>`.
+ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
+ match self.kind() {
+ ty::Infer(ty::IntVar(_) | 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.is_trivially_sized(tcx)),
+
+ ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
+
+ ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
+
+ ty::Infer(ty::TyVar(_)) => false,
+
+ ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("`is_trivially_sized` applied to unexpected type: {:?}", self)
+ }
+ }
+ }
+
+ /// Fast path helper for primitives which are always `Copy` and which
+ /// have a side-effect-free `Clone` impl.
+ ///
+ /// Returning true means the type is known to be pure and `Copy+Clone`.
+ /// Returning `false` means nothing -- could be `Copy`, might not be.
+ ///
+ /// This is mostly useful for optimizations, as there are the types
+ /// on which we can replace cloning with dereferencing.
+ pub fn is_trivially_pure_clone_copy(self) -> bool {
+ match self.kind() {
+ ty::Bool | ty::Char | ty::Never => true,
+
+ // These aren't even `Clone`
+ ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false,
+
+ ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+
+ // The voldemort ZSTs are fine.
+ ty::FnDef(..) => true,
+
+ ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
+
+ // A 100-tuple isn't "trivial", so doing this only for reasonable sizes.
+ ty::Tuple(field_tys) => {
+ field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
+ }
+
+ // Sometimes traits aren't implemented for every ABI or arity,
+ // because we can't be generic over everything yet.
+ ty::FnPtr(..) => false,
+
+ // Definitely absolutely not copy.
+ ty::Ref(_, _, hir::Mutability::Mut) => false,
+
+ // Thin pointers & thin shared references are pure-clone-copy, but for
+ // anything with custom metadata it might be more complicated.
+ ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
+
+ ty::Generator(..) | ty::GeneratorWitness(..) => false,
+
+ // Might be, but not "trivial" so just giving the safe answer.
+ ty::Adt(..) | ty::Closure(..) | ty::Opaque(..) => false,
+
+ ty::Projection(..) | ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
+
+ ty::Bound(..) | ty::Placeholder(..) => {
+ bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self);
+ }
+ }
+ }
+}
+
+/// Extra information about why we ended up with a particular variance.
+/// This is only used to add more information to error messages, and
+/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
+/// may lead to confusing notes in error messages, it will never cause
+/// a miscompilation or unsoundness.
+///
+/// When in doubt, use `VarianceDiagInfo::default()`
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagInfo<'tcx> {
+ /// No additional information - this is the default.
+ /// We will not add any additional information to error messages.
+ #[default]
+ None,
+ /// We switched our variance because a generic argument occurs inside
+ /// the invariant generic argument of another type.
+ Invariant {
+ /// The generic type containing the generic parameter
+ /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
+ ty: Ty<'tcx>,
+ /// The index of the generic parameter being used
+ /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
+ param_index: u32,
+ },
+}
+
+impl<'tcx> VarianceDiagInfo<'tcx> {
+ /// Mirrors `Variance::xform` - used to 'combine' the existing
+ /// and new `VarianceDiagInfo`s when our variance changes.
+ pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
+ // For now, just use the first `VarianceDiagInfo::Invariant` that we see
+ match self {
+ VarianceDiagInfo::None => other,
+ VarianceDiagInfo::Invariant { .. } => self,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
new file mode 100644
index 000000000..6262aa180
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -0,0 +1,785 @@
+// Type substitutions.
+
+use crate::mir;
+use crate::ty::codec::{TyDecoder, TyEncoder};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
+use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
+
+use rustc_data_structures::intern::{Interned, WithStableHash};
+use rustc_hir::def_id::DefId;
+use rustc_macros::HashStable;
+use rustc_serialize::{self, Decodable, Encodable};
+use smallvec::SmallVec;
+
+use core::intrinsics;
+use std::cmp::Ordering;
+use std::fmt;
+use std::marker::PhantomData;
+use std::mem;
+use std::num::NonZeroUsize;
+use std::ops::ControlFlow;
+use std::slice;
+
+/// 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 an interned pointer,
+/// with the lowest 2 bits being reserved for a tag to
+/// indicate the type (`Ty`, `Region`, or `Const`) it points to.
+///
+/// Note: the `PartialEq`, `Eq` and `Hash` derives are only valid because `Ty`,
+/// `Region` and `Const` are all interned.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct GenericArg<'tcx> {
+ ptr: NonZeroUsize,
+ marker: PhantomData<(Ty<'tcx>, ty::Region<'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, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord)]
+pub enum GenericArgKind<'tcx> {
+ Lifetime(ty::Region<'tcx>),
+ Type(Ty<'tcx>),
+ Const(ty::Const<'tcx>),
+}
+
+/// This function goes from `&'a [Ty<'tcx>]` to `&'a [GenericArg<'tcx>]`
+///
+/// This is sound as, for types, `GenericArg` is just
+/// `NonZeroUsize::new_unchecked(ty as *const _ as usize)` as
+/// long as we use `0` for the `TYPE_TAG`.
+pub fn ty_slice_as_generic_args<'a, 'tcx>(ts: &'a [Ty<'tcx>]) -> &'a [GenericArg<'tcx>] {
+ assert_eq!(TYPE_TAG, 0);
+ // SAFETY: the whole slice is valid and immutable.
+ // `Ty` and `GenericArg` is explained above.
+ unsafe { slice::from_raw_parts(ts.as_ptr().cast(), ts.len()) }
+}
+
+impl<'tcx> List<Ty<'tcx>> {
+ /// Allows to freely switch between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`.
+ ///
+ /// As lists are interned, `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>` have
+ /// be interned together, see `intern_type_list` for more details.
+ #[inline]
+ pub fn as_substs(&'tcx self) -> SubstsRef<'tcx> {
+ assert_eq!(TYPE_TAG, 0);
+ // SAFETY: `List<T>` is `#[repr(C)]`. `Ty` and `GenericArg` is explained above.
+ unsafe { &*(self as *const List<Ty<'tcx>> as *const List<GenericArg<'tcx>>) }
+ }
+}
+
+impl<'tcx> GenericArgKind<'tcx> {
+ #[inline]
+ 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.0.0) & TAG_MASK, 0);
+ (REGION_TAG, lt.0.0 as *const ty::RegionKind<'tcx> as usize)
+ }
+ GenericArgKind::Type(ty) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
+ (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
+ }
+ GenericArgKind::Const(ct) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
+ (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
+ }
+ };
+
+ GenericArg { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
+ }
+}
+
+impl<'tcx> 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<'tcx>) -> Ordering {
+ self.unpack().cmp(&other.unpack())
+ }
+}
+
+impl<'tcx> PartialOrd for GenericArg<'tcx> {
+ fn partial_cmp(&self, other: &GenericArg<'tcx>) -> Option<Ordering> {
+ Some(self.cmp(&other))
+ }
+}
+
+impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> {
+ #[inline]
+ fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> {
+ GenericArgKind::Lifetime(r).pack()
+ }
+}
+
+impl<'tcx> From<Ty<'tcx>> for GenericArg<'tcx> {
+ #[inline]
+ fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> {
+ GenericArgKind::Type(ty).pack()
+ }
+}
+
+impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> {
+ #[inline]
+ fn from(c: 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();
+ // SAFETY: use of `Interned::new_unchecked` here is ok because these
+ // pointers were originally created from `Interned` types in `pack()`,
+ // and this is just going in the other direction.
+ unsafe {
+ match ptr & TAG_MASK {
+ REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>),
+ ))),
+ TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
+ ))),
+ CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
+ &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+ ))),
+ _ => intrinsics::unreachable(),
+ }
+ }
+ }
+
+ /// Unpack the `GenericArg` as a region when it is known certainly to be a region.
+ pub fn expect_region(self) -> ty::Region<'tcx> {
+ match self.unpack() {
+ GenericArgKind::Lifetime(lt) => lt,
+ _ => bug!("expected a region, but found another kind"),
+ }
+ }
+
+ /// 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"),
+ }
+ }
+
+ /// Unpack the `GenericArg` as a const when it is known certainly to be a const.
+ pub fn expect_const(self) -> ty::Const<'tcx> {
+ match self.unpack() {
+ GenericArgKind::Const(c) => c,
+ _ => bug!("expected a const, 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(lt).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 try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ match self.unpack() {
+ GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
+ GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
+ GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for GenericArg<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ 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, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for GenericArg<'tcx> {
+ fn encode(&self, e: &mut E) {
+ self.unpack().encode(e)
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for GenericArg<'tcx> {
+ fn decode(d: &mut D) -> GenericArg<'tcx> {
+ 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<'tcx> InternalSubsts<'tcx> {
+ /// Checks whether all elements of this list are types, if so, transmute.
+ pub fn try_as_type_list(&'tcx self) -> Option<&'tcx List<Ty<'tcx>>> {
+ if self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))) {
+ assert_eq!(TYPE_TAG, 0);
+ // SAFETY: All elements are types, see `List<Ty<'tcx>>::as_substs`.
+ Some(unsafe { &*(self as *const List<GenericArg<'tcx>> as *const List<Ty<'tcx>>) })
+ } else {
+ None
+ }
+ }
+
+ /// 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(&'tcx self) -> ClosureSubsts<'tcx> {
+ ClosureSubsts { substs: self }
+ }
+
+ /// Interpret these substitutions as the substitutions of a generator type.
+ /// Generator 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 }
+ }
+
+ /// Interpret these substitutions as the substitutions of an inline const.
+ /// Inline const substitutions have a particular structure controlled by the
+ /// compiler that encodes information like the inferred type;
+ /// see `ty::InlineConstSubsts` struct for more comments.
+ pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts { substs: self }
+ }
+
+ /// Creates an `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 an `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))
+ })
+ }
+
+ pub 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)
+ }
+
+ pub 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);
+ }
+ }
+
+ #[inline]
+ pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
+ self.iter()
+ .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None })
+ }
+
+ #[inline]
+ pub fn regions(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'tcx {
+ self.iter().filter_map(|k| {
+ if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None }
+ })
+ }
+
+ #[inline]
+ pub fn consts(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'tcx {
+ self.iter().filter_map(|k| {
+ if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None }
+ })
+ }
+
+ #[inline]
+ pub fn non_erasable_generics(
+ &'tcx self,
+ ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx {
+ 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) -> 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.
+ ///
+ /// For example given:
+ ///
+ /// ```no_run
+ /// trait X<S> { fn f<T>(); }
+ /// impl<U> X<U> for U { fn f<V>() {} }
+ /// ```
+ ///
+ /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait.
+ /// * If `source_ancestor` is the def_id of the trait.
+ /// * If `target_substs` is `[U]`, the substs for the impl.
+ /// * Then we will return `[U, T]`, the subst for `f` in the impl that
+ /// are needed for it to match the trait.
+ 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.iter().skip(defs.params.len())))
+ }
+
+ pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> {
+ tcx.mk_substs(self.iter().take(generics.count()))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ // 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].try_fold_with(folder)?;
+ if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) }
+ }
+ 2 => {
+ let param0 = self[0].try_fold_with(folder)?;
+ let param1 = self[1].try_fold_with(folder)?;
+ if param0 == self[0] && param1 == self[1] {
+ Ok(self)
+ } else {
+ Ok(folder.tcx().intern_substs(&[param0, param1]))
+ }
+ }
+ 0 => Ok(self),
+ _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_substs(v)),
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for SubstsRef<'tcx> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ // This code is fairly hot, though not as hot as `SubstsRef`.
+ //
+ // When compiling stage 2, I get the following results:
+ //
+ // len | total | %
+ // --- | --------- | -----
+ // 2 | 15083590 | 48.1
+ // 3 | 7540067 | 24.0
+ // 1 | 5300377 | 16.9
+ // 4 | 1351897 | 4.3
+ // 0 | 1256849 | 4.0
+ //
+ // I've tried it with some private repositories and got
+ // close to the same result, with 4 and 0 swapping places
+ // sometimes.
+ match self.len() {
+ 2 => {
+ let param0 = self[0].try_fold_with(folder)?;
+ let param1 = self[1].try_fold_with(folder)?;
+ if param0 == self[0] && param1 == self[1] {
+ Ok(self)
+ } else {
+ Ok(folder.tcx().intern_type_list(&[param0, param1]))
+ }
+ }
+ _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)),
+ }
+ }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`.
+#[rustc_on_unimplemented(message = "Calling `subst` must now be done through an `EarlyBinder`")]
+pub trait Subst<'tcx>: Sized {
+ type Inner;
+
+ fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner;
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for ty::EarlyBinder<T> {
+ type Inner = T;
+
+ fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner {
+ let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
+ self.0.fold_with(&mut folder)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// The actual substitution engine itself is a type folder.
+
+struct SubstFolder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ substs: &'a [GenericArg<'tcx>],
+
+ /// Number of region binders we have passed through while doing the substitution
+ binders_passed: u32,
+}
+
+impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
+ #[inline]
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> ty::Binder<'tcx, 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> {
+ #[cold]
+ #[inline(never)]
+ fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
+ bug!(
+ "Region parameter out of range when substituting in region {} (index={})",
+ data.name,
+ data.index
+ )
+ }
+
+ // 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),
+ _ => region_param_out_of_range(data),
+ }
+ }
+ _ => r,
+ }
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if !t.needs_subst() {
+ return t;
+ }
+
+ match *t.kind() {
+ ty::Param(p) => self.ty_for_param(p, t),
+ _ => t.super_fold_with(self),
+ }
+ }
+
+ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Param(p) = c.kind() {
+ self.const_for_param(p, c)
+ } else {
+ c.super_fold_with(self)
+ }
+ }
+
+ #[inline]
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ 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) => self.type_param_expected(p, source_ty, kind),
+ None => self.type_param_out_of_range(p, source_ty),
+ };
+
+ self.shift_vars_through_binders(ty)
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
+ bug!(
+ "expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, substs={:?}",
+ p,
+ ty,
+ p.index,
+ kind,
+ self.substs,
+ )
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
+ bug!(
+ "type parameter `{:?}` ({:?}/{}) out of range when substituting, substs={:?}",
+ p,
+ ty,
+ p.index,
+ self.substs,
+ )
+ }
+
+ fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'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) => self.const_param_expected(p, source_ct, kind),
+ None => self.const_param_out_of_range(p, source_ct),
+ };
+
+ self.shift_vars_through_binders(ct)
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn const_param_expected(
+ &self,
+ p: ty::ParamConst,
+ ct: ty::Const<'tcx>,
+ kind: GenericArgKind<'tcx>,
+ ) -> ! {
+ bug!(
+ "expected const for `{:?}` ({:?}/{}) but found {:?} when substituting substs={:?}",
+ p,
+ ct,
+ p.index,
+ kind,
+ self.substs,
+ )
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
+ bug!(
+ "const parameter `{:?}` ({:?}/{}) out of range when substituting substs={:?}",
+ p,
+ ct,
+ p.index,
+ self.substs,
+ )
+ }
+
+ /// 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 i32>);
+ /// ```
+ ///
+ /// The type `MetaFunc`, when fully expanded, will be
+ /// ```ignore (illustrative)
+ /// for<'a> fn(fn(&'a i32))
+ /// // ^~ ^~ ^~~
+ /// // | | |
+ /// // | | 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 i32` 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 i32>);
+ /// ```
+ ///
+ /// Here the final type will be:
+ /// ```ignore (illustrative)
+ /// for<'a> fn((&'a i32, fn(&'a i32)))
+ /// // ^~~ ^~~
+ /// // | |
+ /// // DebruijnIndex of 1 |
+ /// // DebruijnIndex of 2
+ /// ```
+ /// As indicated in the diagram, here the same type `&'a i32` 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(TypeFolder::tcx(self), 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)
+ }
+}
+
+/// 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, 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:
+///
+/// ```ignore (illustrative)
+/// 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, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct UserSelfTy<'tcx> {
+ pub impl_def_id: DefId,
+ pub self_ty: Ty<'tcx>,
+}
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
new file mode 100644
index 000000000..541dace5c
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -0,0 +1,272 @@
+use crate::traits::specialization_graph;
+use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use crate::ty::visit::TypeVisitable;
+use crate::ty::{Ident, Ty, TyCtxt};
+use hir::def_id::LOCAL_CRATE;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use std::iter;
+
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_errors::ErrorGuaranteed;
+use rustc_macros::HashStable;
+
+/// A trait's definition with type information.
+#[derive(HashStable, Encodable, Decodable)]
+pub struct TraitDef {
+ 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,
+
+ /// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]`
+ /// attribute, indicating that editions before 2021 should not consider this trait
+ /// during method dispatch if the receiver is an array.
+ pub skip_array_during_method_dispatch: bool,
+
+ /// Used to determine whether the standard library is allowed to specialize
+ /// on this trait.
+ pub specialization_kind: TraitSpecializationKind,
+
+ /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which
+ /// must be implemented.
+ pub must_implement_one_of: Option<Box<[Ident]>>,
+}
+
+/// Whether this trait is treated specially by the standard library
+/// specialization lint.
+#[derive(HashStable, PartialEq, Clone, Copy, Encodable, Decodable)]
+pub enum TraitSpecializationKind {
+ /// The default. Specializing on this trait is not allowed.
+ None,
+ /// Specializing on this trait is allowed because it doesn't have any
+ /// methods. For example `Sized` or `FusedIterator`.
+ /// Applies to traits with the `rustc_unsafe_specialization_marker`
+ /// attribute.
+ Marker,
+ /// Specializing on this trait is allowed because all of the impls of this
+ /// trait are "always applicable". Always applicable means that if
+ /// `X<'x>: T<'y>` for any lifetimes, then `for<'a, 'b> X<'a>: T<'b>`.
+ /// Applies to traits with the `rustc_specialization_trait` attribute.
+ AlwaysApplicable,
+}
+
+#[derive(Default, Debug, HashStable)]
+pub struct TraitImpls {
+ blanket_impls: Vec<DefId>,
+ /// Impls indexed by their simplified self type, for fast lookup.
+ non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>,
+}
+
+impl TraitImpls {
+ pub fn blanket_impls(&self) -> &[DefId] {
+ self.blanket_impls.as_slice()
+ }
+
+ pub fn non_blanket_impls(&self) -> &FxIndexMap<SimplifiedType, Vec<DefId>> {
+ &self.non_blanket_impls
+ }
+}
+
+impl<'tcx> TraitDef {
+ pub fn new(
+ def_id: DefId,
+ unsafety: hir::Unsafety,
+ paren_sugar: bool,
+ has_auto_impl: bool,
+ is_marker: bool,
+ skip_array_during_method_dispatch: bool,
+ specialization_kind: TraitSpecializationKind,
+ must_implement_one_of: Option<Box<[Ident]>>,
+ ) -> TraitDef {
+ TraitDef {
+ def_id,
+ unsafety,
+ paren_sugar,
+ has_auto_impl,
+ is_marker,
+ skip_array_during_method_dispatch,
+ specialization_kind,
+ must_implement_one_of,
+ }
+ }
+
+ pub fn ancestors(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ of_impl: DefId,
+ ) -> Result<specialization_graph::Ancestors<'tcx>, ErrorGuaranteed> {
+ 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 _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| {
+ f(did);
+ None
+ });
+ }
+
+ pub fn non_blanket_impls_for_ty(
+ self,
+ def_id: DefId,
+ self_ty: Ty<'tcx>,
+ ) -> impl Iterator<Item = DefId> + 'tcx {
+ let impls = self.trait_impls_of(def_id);
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
+ if let Some(impls) = impls.non_blanket_impls.get(&simp) {
+ return impls.iter().copied();
+ }
+ }
+
+ [].iter().copied()
+ }
+
+ /// Applies function to every impl that could possibly match the self type `self_ty` and returns
+ /// the first non-none value.
+ pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
+ self,
+ def_id: DefId,
+ self_ty: Ty<'tcx>,
+ mut f: F,
+ ) -> Option<T> {
+ // FIXME: This depends on the set of all impls for the trait. That is
+ // unfortunate wrt. incremental compilation.
+ //
+ // If we want to be faster, we could have separate queries for
+ // blanket and non-blanket impls, and compare them separately.
+ let impls = self.trait_impls_of(def_id);
+
+ for &impl_def_id in impls.blanket_impls.iter() {
+ if let result @ Some(_) = f(impl_def_id) {
+ return result;
+ }
+ }
+
+ // Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using
+ // `TreatParams::AsInfer` while actually adding them.
+ //
+ // This way, when searching for some impl for `T: Trait`, we do not look at any impls
+ // whose outer level is not a parameter or projection. Especially for things like
+ // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
+ // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) {
+ if let Some(impls) = impls.non_blanket_impls.get(&simp) {
+ for &impl_def_id in impls {
+ if let result @ Some(_) = f(impl_def_id) {
+ return result;
+ }
+ }
+ }
+ } else {
+ for &impl_def_id in impls.non_blanket_impls.values().flatten() {
+ if let result @ Some(_) = f(impl_def_id) {
+ return result;
+ }
+ }
+ }
+
+ None
+ }
+
+ /// Returns an iterator containing all impls
+ pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
+ let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
+
+ blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned()
+ }
+}
+
+// Query provider for `trait_impls_of`.
+pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls {
+ let mut impls = TraitImpls::default();
+
+ // 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 &(impl_def_id, simplified_self_ty) in
+ tcx.implementations_of_trait((cnum, trait_id)).iter()
+ {
+ if let Some(simplified_self_ty) = simplified_self_ty {
+ impls
+ .non_blanket_impls
+ .entry(simplified_self_ty)
+ .or_default()
+ .push(impl_def_id);
+ } else {
+ impls.blanket_impls.push(impl_def_id);
+ }
+ }
+ }
+ }
+
+ for &impl_def_id in tcx.hir().trait_impls(trait_id) {
+ let impl_def_id = impl_def_id.to_def_id();
+
+ let impl_self_ty = tcx.type_of(impl_def_id);
+ if impl_self_ty.references_error() {
+ continue;
+ }
+
+ if let Some(simplified_self_ty) =
+ fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer)
+ {
+ impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
+ } else {
+ impls.blanket_impls.push(impl_def_id);
+ }
+ }
+
+ impls
+}
+
+// Query provider for `incoherent_impls`.
+#[instrument(level = "debug", skip(tcx))]
+pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
+ let mut impls = Vec::new();
+
+ for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) {
+ for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) {
+ impls.push(impl_def_id)
+ }
+ }
+
+ debug!(?impls);
+
+ tcx.arena.alloc_slice(&impls)
+}
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
new file mode 100644
index 000000000..591bb7831
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -0,0 +1,1294 @@
+//! Miscellaneous type-system utilities that are too small to deserve their own modules.
+
+use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::ty::layout::IntegerExt;
+use crate::ty::query::TyCtxtAt;
+use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
+use crate::ty::{
+ self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitable,
+};
+use rustc_apfloat::Float as _;
+use rustc_ast as ast;
+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_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::GrowableBitSet;
+use rustc_macros::HashStable;
+use rustc_span::{sym, DUMMY_SP};
+use rustc_target::abi::{Integer, Size, TargetDataLayout};
+use rustc_target::spec::abi::Abi;
+use smallvec::SmallVec;
+use std::{fmt, iter};
+
+#[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>,
+}
+
+/// Used as an input to [`TyCtxt::uses_unique_generic_params`].
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum IgnoreRegions {
+ Yes,
+ No,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum NotUniqueParam<'tcx> {
+ DuplicateParam(ty::GenericArg<'tcx>),
+ NotParam(ty::GenericArg<'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_int_ty(&tcx, ity).size());
+ let x = self.val;
+ // sign extend the raw representation to be an i128
+ let x = size.sign_extend(x) as i128;
+ write!(fmt, "{}", x)
+ }
+ _ => write!(fmt, "{}", self.val),
+ }
+ }
+}
+
+fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) {
+ let (int, signed) = match *ty.kind() {
+ ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
+ ty::Uint(uty) => (Integer::from_uint_ty(&tcx, 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 = size.signed_int_min();
+ let max = size.signed_int_max();
+ let val = size.sign_extend(self.val) as i128;
+ assert!(n < (i128::MAX 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 = size.truncate(val);
+ (val, oflo)
+ } else {
+ let max = size.unsigned_int_max();
+ 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))
+ }
+ }
+}
+
+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 {
+ // 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);
+
+ self.with_stable_hashing_context(|mut hcx| {
+ let mut hasher = StableHasher::new();
+ hcx.while_hashing_spans(false, |hcx| ty.hash_stable(hcx, &mut hasher));
+ hasher.finish()
+ })
+ }
+
+ pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
+ match res {
+ Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {
+ Some(self.parent(self.parent(def_id)))
+ }
+ Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
+ Some(self.parent(def_id))
+ }
+ // Other `DefKind`s don't have generics and would ICE when calling
+ // `generics_of`.
+ Res::Def(
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Trait
+ | DefKind::OpaqueTy
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::TraitAlias
+ | DefKind::AssocTy
+ | DefKind::Fn
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::Impl,
+ def_id,
+ ) => Some(def_id),
+ Res::Err => None,
+ _ => None,
+ }
+ }
+
+ 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 ty::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>,
+ mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+ // This is currently used to allow us to walk a ValTree
+ // in lockstep with the type in order to get the ValTree branch that
+ // corresponds to an unsized field.
+ mut f: impl FnMut() -> (),
+ ) -> Ty<'tcx> {
+ let recursion_limit = self.recursion_limit();
+ for iteration in 0.. {
+ if !recursion_limit.value_within_limit(iteration) {
+ return self.ty_error_with_message(
+ DUMMY_SP,
+ &format!("reached the recursion limit finding the struct tail for {}", ty),
+ );
+ }
+ match *ty.kind() {
+ ty::Adt(def, substs) => {
+ if !def.is_struct() {
+ break;
+ }
+ match def.non_enum_variant().fields.last() {
+ Some(field) => {
+ f();
+ ty = field.ty(self, substs);
+ }
+ None => break,
+ }
+ }
+
+ ty::Tuple(tys) if let Some((&last_ty, _)) = tys.split_last() => {
+ f();
+ ty = last_ty;
+ }
+
+ ty::Tuple(_) => 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()) {
+ (&ty::Adt(a_def, a_substs), &ty::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;
+ }
+ }
+ (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() => {
+ if let Some(&a_last) = a_tys.last() {
+ a = a_last;
+ b = *b_tys.last().unwrap();
+ } 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: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
+ ) -> Option<ty::Destructor> {
+ let drop_trait = self.lang_items().drop_trait()?;
+ self.ensure().coherent_trait(drop_trait);
+
+ let ty = self.type_of(adt_did);
+ let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
+ if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
+ if validate(self, impl_did).is_ok() {
+ return Some((*item_id, self.constness(impl_did)));
+ }
+ }
+ None
+ })?;
+
+ Some(ty::Destructor { did, constness })
+ }
+
+ /// 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: ty::AdtDef<'tcx>) -> 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.parent(dtor);
+ 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 = iter::zip(item_substs, impl_substs)
+ .filter(|&(_, k)| {
+ match k.unpack() {
+ GenericArgKind::Lifetime(region) => match region.kind() {
+ ty::ReEarlyBound(ref ebr) => {
+ !impl_generics.region_param(ebr, self).pure_wrt_drop
+ }
+ // Error: not a region param
+ _ => false,
+ },
+ GenericArgKind::Type(ty) => match ty.kind() {
+ ty::Param(ref pt) => !impl_generics.type_param(pt, self).pure_wrt_drop,
+ // Error: not a type param
+ _ => false,
+ },
+ GenericArgKind::Const(ct) => match ct.kind() {
+ ty::ConstKind::Param(ref pc) => {
+ !impl_generics.const_param(pc, self).pure_wrt_drop
+ }
+ // Error: not a const param
+ _ => false,
+ },
+ }
+ })
+ .map(|(item_param, _)| item_param)
+ .collect();
+ debug!("destructor_constraint({:?}) = {:?}", def.did(), result);
+ result
+ }
+
+ /// Checks whether each generic argument is simply a unique generic parameter.
+ pub fn uses_unique_generic_params(
+ self,
+ substs: SubstsRef<'tcx>,
+ ignore_regions: IgnoreRegions,
+ ) -> Result<(), NotUniqueParam<'tcx>> {
+ let mut seen = GrowableBitSet::default();
+ for arg in substs {
+ match arg.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ if ignore_regions == IgnoreRegions::No {
+ let ty::ReEarlyBound(p) = lt.kind() else {
+ return Err(NotUniqueParam::NotParam(lt.into()))
+ };
+ if !seen.insert(p.index) {
+ return Err(NotUniqueParam::DuplicateParam(lt.into()));
+ }
+ }
+ }
+ GenericArgKind::Type(t) => match t.kind() {
+ ty::Param(p) => {
+ if !seen.insert(p.index) {
+ return Err(NotUniqueParam::DuplicateParam(t.into()));
+ }
+ }
+ _ => return Err(NotUniqueParam::NotParam(t.into())),
+ },
+ GenericArgKind::Const(c) => match c.kind() {
+ ty::ConstKind::Param(p) => {
+ if !seen.insert(p.index) {
+ return Err(NotUniqueParam::DuplicateParam(c.into()));
+ }
+ }
+ _ => return Err(NotUniqueParam::NotParam(c.into())),
+ },
+ }
+ }
+
+ Ok(())
+ }
+
+ /// 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 {
+ matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
+ }
+
+ /// Returns `true` if `def_id` refers to a definition that does not have its own
+ /// type-checking context, i.e. closure, generator or inline const.
+ pub fn is_typeck_child(self, def_id: DefId) -> bool {
+ matches!(
+ self.def_kind(def_id),
+ DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+ )
+ }
+
+ /// 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) == 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) == 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 {
+ matches!(self.def_kind(def_id), DefKind::Ctor(..))
+ }
+
+ /// Given the `DefId`, returns the `DefId` of the innermost item that
+ /// has its own type-checking context or "inference environment".
+ ///
+ /// For example, a closure has its own `DefId`, but it is type-checked
+ /// with the containing item. Similarly, an inline const block has its
+ /// own `DefId` but it is type-checked together with the containing item.
+ ///
+ /// Therefore, when we fetch the
+ /// `typeck` the closure, for example, we really wind up
+ /// fetching the `typeck` the enclosing fn item.
+ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
+ let mut def_id = def_id;
+ while self.is_typeck_child(def_id) {
+ def_id = self.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>,
+ env_region: ty::RegionKind<'tcx>,
+ ) -> Option<Ty<'tcx>> {
+ let closure_ty = self.mk_closure(closure_def_id, closure_substs);
+ let closure_kind_ty = closure_substs.as_closure().kind_ty();
+ 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(env_ty)
+ }
+
+ /// Returns `true` if the node pointed to by `def_id` is a `static` item.
+ #[inline]
+ pub fn is_static(self, def_id: DefId) -> bool {
+ matches!(self.def_kind(def_id), DefKind::Static(_))
+ }
+
+ #[inline]
+ pub fn static_mutability(self, def_id: DefId) -> Option<hir::Mutability> {
+ if let DefKind::Static(mt) = self.def_kind(def_id) { Some(mt) } else { None }
+ }
+
+ /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute.
+ pub fn is_thread_local_static(self, def_id: DefId) -> bool {
+ self.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
+ }
+
+ /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item.
+ #[inline]
+ 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));
+
+ // Make sure that accesses to unsafe statics end up using raw pointers.
+ // For thread-locals, this needs to be kept in sync with `Rvalue::ty`.
+ if self.is_mutable_static(def_id) {
+ self.mk_mut_ptr(static_ty)
+ } else if self.is_foreign_item(def_id) {
+ self.mk_imm_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.
+ #[instrument(skip(self), level = "debug")]
+ pub fn try_expand_impl_trait_type(
+ self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ ) -> Result<Ty<'tcx>, Ty<'tcx>> {
+ let mut visitor = OpaqueTypeExpander {
+ seen_opaque_tys: FxHashSet::default(),
+ expanded_cache: FxHashMap::default(),
+ primary_def_id: Some(def_id),
+ found_recursion: false,
+ found_any_recursion: false,
+ check_recursion: true,
+ tcx: self,
+ };
+
+ let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap();
+ trace!(?expanded_type);
+ if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
+ }
+
+ pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
+ ty::EarlyBinder(self.type_of(def_id))
+ }
+
+ pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
+ ty::EarlyBinder(self.fn_sig(def_id))
+ }
+
+ pub fn bound_impl_trait_ref(
+ self,
+ def_id: DefId,
+ ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
+ self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
+ }
+
+ pub fn bound_explicit_item_bounds(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> {
+ ty::EarlyBinder(self.explicit_item_bounds(def_id))
+ }
+
+ pub fn bound_item_bounds(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
+ ty::EarlyBinder(self.item_bounds(def_id))
+ }
+
+ pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
+ ty::EarlyBinder(self.const_param_default(def_id))
+ }
+
+ pub fn bound_predicates_of(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+ ty::EarlyBinder(self.predicates_of(def_id))
+ }
+
+ pub fn bound_explicit_predicates_of(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+ ty::EarlyBinder(self.explicit_predicates_of(def_id))
+ }
+
+ pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
+ ty::EarlyBinder(self.impl_subject(def_id))
+ }
+}
+
+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: Option<DefId>,
+ found_recursion: bool,
+ found_any_recursion: bool,
+ /// Whether or not to check for recursive opaque types.
+ /// This is `true` when we're explicitly checking for opaque type
+ /// recursion, and 'false' otherwise to avoid unnecessary work.
+ check_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_any_recursion {
+ return None;
+ }
+ let substs = substs.fold_with(self);
+ if !self.check_recursion || 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.bound_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
+ }
+ };
+ if self.check_recursion {
+ 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_any_recursion = true;
+ self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
+ 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
+ }
+ }
+}
+
+impl<'tcx> Ty<'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(self, tcx: TyCtxt<'tcx>) -> Option<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 { size.signed_int_max() as u128 } else { size.unsigned_int_max() };
+ Some(val)
+ }
+ ty::Char => Some(std::char::MAX as u128),
+ ty::Float(fty) => Some(match fty {
+ ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
+ ty::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(self, tcx: TyCtxt<'tcx>) -> Option<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 { size.truncate(size.signed_int_min() as u128) } else { 0 };
+ Some(val)
+ }
+ ty::Char => Some(0),
+ ty::Float(fty) => Some(match fty {
+ ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
+ ty::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(
+ self,
+ tcx_at: TyCtxtAt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> bool {
+ self.is_trivially_pure_clone_copy() || tcx_at.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(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 an
+ /// `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(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_freeze() || tcx_at.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(fields) => fields.iter().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(_) => false,
+ }
+ }
+
+ /// Checks whether values of this type `T` implement the `Unpin` trait.
+ pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
+ }
+
+ /// Fast path helper for testing if a type is `Unpin`.
+ ///
+ /// Returning true means the type is known to be `Unpin`. Returning
+ /// `false` means nothing -- could be `Unpin`, might not be.
+ fn is_trivially_unpin(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(fields) => fields.iter().all(Self::is_trivially_unpin),
+ ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
+ ty::Adt(..)
+ | ty::Bound(..)
+ | ty::Closure(..)
+ | ty::Dynamic(..)
+ | ty::Foreign(_)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(_)
+ | ty::Infer(_)
+ | ty::Opaque(..)
+ | ty::Param(_)
+ | ty::Placeholder(_)
+ | ty::Projection(_) => 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(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.
+ // If normalization fails, we just use `query_ty`.
+ let query_ty =
+ tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
+
+ tcx.needs_drop_raw(param_env.and(query_ty))
+ }
+ }
+ }
+
+ /// Checks if `ty` has has a significant drop.
+ ///
+ /// Note that this method can return false even if `ty` has a destructor
+ /// attached; even if that is the case then the adt has been marked with
+ /// the attribute `rustc_insignificant_dtor`.
+ ///
+ /// Note that this method is used to check for change in drop order for
+ /// 2229 drop reorder migration analysis.
+ #[inline]
+ pub fn has_significant_drop(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,
+ };
+
+ // FIXME(#86868): We should be canonicalizing, or else moving this to a method of inference
+ // context, or *something* like that, but for now just avoid passing inference
+ // variables to queries that can't cope with them. Instead, conservatively
+ // return "true" (may change drop order).
+ if query_ty.needs_infer() {
+ return true;
+ }
+
+ // 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.has_significant_drop_raw(param_env.and(erased))
+ }
+ }
+ }
+
+ /// Returns `true` if equality for this type is both reflexive and structural.
+ ///
+ /// Reflexive equality for a type is indicated by an `Eq` impl for that type.
+ ///
+ /// Primitive types (`u32`, `str`) have structural equality by definition. For composite data
+ /// types, equality for the type as a whole is structural when it is the same as equality
+ /// between all components (fields, array elements, etc.) of that type. For ADTs, structural
+ /// equality is indicated by an implementation of `PartialStructuralEq` and `StructuralEq` for
+ /// that type.
+ ///
+ /// This function is "shallow" because it may return `true` for a composite type whose fields
+ /// are not `StructuralEq`. For example, `[T; 4]` has structural equality regardless of `T`
+ /// because equality for arrays is determined by the equality of each array element. If you
+ /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way
+ /// down, you will need to use a type visitor.
+ #[inline]
+ pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
+ match self.kind() {
+ // Look for an impl of both `PartialStructuralEq` and `StructuralEq`.
+ ty::Adt(..) => tcx.has_structural_eq_impls(self),
+
+ // Primitive types that satisfy `Eq`.
+ ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => true,
+
+ // Composite types that satisfy `Eq` when all of their fields do.
+ //
+ // Because this function is "shallow", we return `true` for these composites regardless
+ // of the type(s) contained within.
+ ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
+
+ // Raw pointers use bitwise comparison.
+ ty::RawPtr(_) | ty::FnPtr(_) => true,
+
+ // Floating point numbers are not `Eq`.
+ ty::Float(_) => false,
+
+ // Conservatively return `false` for all others...
+
+ // Anonymous function types
+ ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Generator(..) => false,
+
+ // Generic or inferred types
+ //
+ // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be
+ // called for known, fully-monomorphized types.
+ ty::Projection(_)
+ | ty::Opaque(..)
+ | ty::Param(_)
+ | ty::Bound(..)
+ | ty::Placeholder(_)
+ | ty::Infer(_) => false,
+
+ ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false,
+ }
+ }
+
+ /// 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(self) -> Ty<'tcx> {
+ let mut ty = self;
+ while let ty::Ref(_, inner_ty, _) = ty.kind() {
+ ty = *inner_ty;
+ }
+ ty
+ }
+
+ #[inline]
+ pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
+ self.0.outer_exclusive_binder
+ }
+}
+
+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:
+ ///
+ /// ```ignore (illustrative)
+ /// 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<'tcx>(
+ 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()),
+
+ 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.kind().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(fields) => fields.iter().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::Param(_)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Opaque(..)
+ | ty::Infer(_)
+ | ty::Closure(..)
+ | ty::Generator(..) => Ok(smallvec![ty]),
+ }
+}
+
+pub fn is_trivially_const_drop<'tcx>(ty: Ty<'tcx>) -> bool {
+ match *ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Str
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Foreign(_) => true,
+
+ ty::Opaque(..)
+ | ty::Dynamic(..)
+ | ty::Error(_)
+ | ty::Bound(..)
+ | ty::Param(_)
+ | ty::Placeholder(_)
+ | ty::Projection(_)
+ | ty::Infer(_) => false,
+
+ // Not trivial because they have components, and instead of looking inside,
+ // we'll just perform trait selection.
+ ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false,
+
+ ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
+
+ ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)),
+ }
+}
+
+// Does the equivalent of
+// ```
+// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
+// folder.tcx().intern_*(&v)
+// ```
+pub fn fold_list<'tcx, F, T>(
+ list: &'tcx ty::List<T>,
+ folder: &mut F,
+ intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
+) -> Result<&'tcx ty::List<T>, F::Error>
+where
+ F: FallibleTypeFolder<'tcx>,
+ T: TypeFoldable<'tcx> + PartialEq + Copy,
+{
+ let mut iter = list.iter();
+ // Look for the first element that changed
+ match iter.by_ref().enumerate().find_map(|(i, t)| match t.try_fold_with(folder) {
+ Ok(new_t) if new_t == t => None,
+ new_t => Some((i, new_t)),
+ }) {
+ Some((i, Ok(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);
+ for t in iter {
+ new_list.push(t.try_fold_with(folder)?)
+ }
+ Ok(intern(folder.tcx(), &new_list))
+ }
+ Some((_, Err(err))) => {
+ return Err(err);
+ }
+ None => Ok(list),
+ }
+}
+
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
+pub struct AlwaysRequiresDrop;
+
+/// Normalizes all opaque types in the given value, replacing them
+/// with their underlying types.
+pub fn normalize_opaque_types<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ val: &'tcx ty::List<ty::Predicate<'tcx>>,
+) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+ let mut visitor = OpaqueTypeExpander {
+ seen_opaque_tys: FxHashSet::default(),
+ expanded_cache: FxHashMap::default(),
+ primary_def_id: None,
+ found_recursion: false,
+ found_any_recursion: false,
+ check_recursion: false,
+ tcx,
+ };
+ val.fold_with(&mut visitor)
+}
+
+/// Determines whether an item is annotated with `doc(hidden)`.
+pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ tcx.get_attrs(def_id, sym::doc)
+ .filter_map(|attr| attr.meta_item_list())
+ .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
+}
+
+/// Determines whether an item is an intrinsic by Abi.
+pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers =
+ ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers }
+}
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
new file mode 100644
index 000000000..536506720
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -0,0 +1,745 @@
+//! A visiting traversal mechanism for complex data structures that contain type
+//! information.
+//!
+//! This is a read-only traversal of the data structure.
+//!
+//! This traversal has limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! visitation. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
+//!
+//! There are three groups of traits involved in each traversal.
+//! - `TypeVisitable`. This is implemented once for many types, including:
+//! - Types of interest, for which the the methods delegate to the
+//! visitor.
+//! - All other types, including generic containers like `Vec` and `Option`.
+//! It defines a "skeleton" of how they should be visited.
+//! - `TypeSuperVisitable`. This is implemented only for each type of interest,
+//! and defines the visiting "skeleton" for these types.
+//! - `TypeVisitor`. This is implemented for each visitor. This defines how
+//! types of interest are visited.
+//!
+//! This means each visit is a mixture of (a) generic visiting operations, and (b)
+//! custom visit operations that are specific to the visitor.
+//! - The `TypeVisitable` impls handle most of the traversal, and call into
+//! `TypeVisitor` when they encounter a type of interest.
+//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of
+//! the types of interest are recursive and can contain other types of interest.
+//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
+//! visitor might provide custom handling only for some types of interest, or
+//! only for some variants of each type of interest, and then use default
+//! traversal for the remaining cases.
+//!
+//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U:
+//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
+//! ```text
+//! s.visit_with(visitor) calls
+//! - ty.visit_with(visitor) calls
+//! - visitor.visit_ty(ty) may call
+//! - ty.super_visit_with(visitor)
+//! - u.visit_with(visitor)
+//! ```
+use crate::mir;
+use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
+use rustc_errors::ErrorGuaranteed;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sso::SsoHashSet;
+use std::fmt;
+use std::ops::ControlFlow;
+
+/// This trait is implemented for every type that can be visited,
+/// providing the skeleton of the traversal.
+///
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
+pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
+ /// The entry point for visiting. To visit a value `t` with a visitor `v`
+ /// call: `t.visit_with(v)`.
+ ///
+ /// For most types, this just traverses the value, calling `visit_with` on
+ /// each field/element.
+ ///
+ /// For types of interest (such as `Ty`), the implementation of this method
+ /// that calls a visitor method specifically for that type (such as
+ /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+ /// `TypeVisitor`.
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+
+ /// 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 }).is_break()
+ }
+
+ /// 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)
+ }
+
+ #[instrument(level = "trace")]
+ fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
+ }
+ 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_ERROR)
+ }
+ fn error_reported(&self) -> Option<ErrorGuaranteed> {
+ if self.references_error() {
+ Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+ } else {
+ None
+ }
+ }
+ fn has_param_types_or_consts(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
+ }
+ fn has_infer_regions(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_RE_INFER)
+ }
+ fn has_infer_types(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_TY_INFER)
+ }
+ fn has_infer_types_or_consts(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
+ }
+ fn needs_infer(&self) -> bool {
+ self.has_type_flags(TypeFlags::NEEDS_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)
+ }
+ /// "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)
+ }
+
+ /// Indicates whether this value still has parameters/placeholders/inference variables
+ /// which could be replaced later, in a way that would change the results of `impl`
+ /// specialization.
+ fn still_further_specializable(&self) -> bool {
+ self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
+ }
+}
+
+pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
+ /// Provides a default visit for a type of interest. This should only be
+ /// called within `TypeVisitor` methods, when a non-custom traversal is
+ /// desired for the value of the type of interest passed to that method.
+ /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
+ /// `ty.super_visit_with(self)`, but any other visiting should be done
+ /// with `xyz.visit_with(self)`.
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+}
+
+/// This trait is implemented for every visiting traversal. There is a visit
+/// method defined for every type of interest. Each such method has a default
+/// that recurses into the type's fields in a non-custom fashion.
+pub trait TypeVisitor<'tcx>: Sized {
+ type BreakTy = !;
+
+ fn visit_binder<T: TypeVisitable<'tcx>>(
+ &mut self,
+ t: &Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ t.super_visit_with(self)
+ }
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ t.super_visit_with(self)
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ r.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ c.super_visit_with(self)
+ }
+
+ fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ uv.super_visit_with(self)
+ }
+
+ fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+ p.super_visit_with(self)
+ }
+
+ fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
+ c.super_visit_with(self)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Region folder
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// Invoke `callback` on every region appearing free in `value`.
+ pub fn for_each_free_region(
+ self,
+ value: &impl TypeVisitable<'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 TypeVisitable<'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 TypeVisitable<'tcx>,
+ callback: impl FnMut(ty::Region<'tcx>) -> bool,
+ ) -> bool {
+ 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:
+ ///
+ /// ```ignore (illustrative)
+ /// 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,
+ {
+ type BreakTy = ();
+
+ fn visit_binder<T: TypeVisitable<'tcx>>(
+ &mut self,
+ t: &Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ self.outer_index.shift_in(1);
+ let result = t.super_visit_with(self);
+ self.outer_index.shift_out(1);
+ result
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
+ ControlFlow::CONTINUE
+ }
+ _ => {
+ if (self.callback)(r) {
+ ControlFlow::BREAK
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // We're only interested in types involving regions
+ if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
+ ty.super_visit_with(self)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+
+ value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
+ }
+
+ /// 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<'tcx, T>,
+ ) -> FxHashSet<ty::BoundRegionKind>
+ where
+ T: TypeVisitable<'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<'tcx, T>,
+ ) -> FxHashSet<ty::BoundRegionKind>
+ where
+ T: TypeVisitable<'tcx>,
+ {
+ self.collect_late_bound_regions(value, false)
+ }
+
+ fn collect_late_bound_regions<T>(
+ self,
+ value: &Binder<'tcx, T>,
+ just_constraint: bool,
+ ) -> FxHashSet<ty::BoundRegionKind>
+ where
+ T: TypeVisitable<'tcx>,
+ {
+ let mut collector = LateBoundRegionsCollector::new(just_constraint);
+ let result = value.as_ref().skip_binder().visit_with(&mut collector);
+ assert!(result.is_continue()); // should never have stopped early
+ collector.regions
+ }
+}
+
+pub struct ValidateBoundVars<'tcx> {
+ bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+ binder_index: ty::DebruijnIndex,
+ // We may encounter the same variable at different levels of binding, so
+ // this can't just be `Ty`
+ visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
+}
+
+impl<'tcx> ValidateBoundVars<'tcx> {
+ pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
+ ValidateBoundVars {
+ bound_vars,
+ binder_index: ty::INNERMOST,
+ visited: SsoHashSet::default(),
+ }
+ }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
+ type BreakTy = ();
+
+ fn visit_binder<T: TypeVisitable<'tcx>>(
+ &mut self,
+ t: &Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ 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>) -> ControlFlow<Self::BreakTy> {
+ if t.outer_exclusive_binder() < self.binder_index
+ || !self.visited.insert((self.binder_index, t))
+ {
+ return ControlFlow::BREAK;
+ }
+ match *t.kind() {
+ ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
+ if self.bound_vars.len() <= bound_ty.var.as_usize() {
+ bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
+ }
+ let list_var = self.bound_vars[bound_ty.var.as_usize()];
+ match list_var {
+ ty::BoundVariableKind::Ty(kind) => {
+ if kind != bound_ty.kind {
+ bug!(
+ "Mismatched type kinds: {:?} doesn't var in list {:?}",
+ bound_ty.kind,
+ list_var
+ );
+ }
+ }
+ _ => {
+ bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
+ }
+ }
+ }
+
+ _ => (),
+ };
+
+ t.super_visit_with(self)
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ ty::ReLateBound(index, br) if index == self.binder_index => {
+ if self.bound_vars.len() <= br.var.as_usize() {
+ bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
+ }
+ let list_var = self.bound_vars[br.var.as_usize()];
+ match list_var {
+ ty::BoundVariableKind::Region(kind) => {
+ if kind != br.kind {
+ bug!(
+ "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
+ br.kind,
+ list_var,
+ self.bound_vars
+ );
+ }
+ }
+ _ => bug!(
+ "Mismatched bound variable kinds! Expected region, found {:?}",
+ list_var
+ ),
+ }
+ }
+
+ _ => (),
+ };
+
+ r.super_visit_with(self)
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundEscapingVars;
+
+/// 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 {
+ type BreakTy = FoundEscapingVars;
+
+ fn visit_binder<T: TypeVisitable<'tcx>>(
+ &mut self,
+ t: &Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ self.outer_index.shift_in(1);
+ let result = t.super_visit_with(self);
+ self.outer_index.shift_out(1);
+ result
+ }
+
+ #[inline]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // 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.
+ if t.outer_exclusive_binder() > self.outer_index {
+ ControlFlow::Break(FoundEscapingVars)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // If the region is bound by `outer_index` or anything outside
+ // of outer index, then it escapes the binders we have
+ // visited.
+ if r.bound_at_or_above_binder(self.outer_index) {
+ ControlFlow::Break(FoundEscapingVars)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // 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.kind() {
+ ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
+ ControlFlow::Break(FoundEscapingVars)
+ }
+ _ => ct.super_visit_with(self),
+ }
+ }
+
+ #[inline]
+ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if predicate.outer_exclusive_binder() > self.outer_index {
+ ControlFlow::Break(FoundEscapingVars)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundFlags;
+
+// FIXME: Optimize for checking for infer flags
+struct HasTypeFlagsVisitor {
+ flags: ty::TypeFlags,
+}
+
+impl std::fmt::Debug for HasTypeFlagsVisitor {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.flags.fmt(fmt)
+ }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
+ type BreakTy = FoundFlags;
+
+ #[inline]
+ #[instrument(skip(self), level = "trace")]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = t.flags();
+ trace!(t.flags=?t.flags());
+ if flags.intersects(self.flags) {
+ ControlFlow::Break(FoundFlags)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ #[instrument(skip(self), level = "trace")]
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = r.type_flags();
+ trace!(r.flags=?flags);
+ if flags.intersects(self.flags) {
+ ControlFlow::Break(FoundFlags)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ #[instrument(level = "trace")]
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = FlagComputation::for_const(c);
+ trace!(r.flags=?flags);
+ if flags.intersects(self.flags) {
+ ControlFlow::Break(FoundFlags)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ #[instrument(level = "trace")]
+ fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = FlagComputation::for_unevaluated_const(uv);
+ trace!(r.flags=?flags);
+ if flags.intersects(self.flags) {
+ ControlFlow::Break(FoundFlags)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ #[instrument(level = "trace")]
+ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+ debug!(
+ "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+ predicate,
+ predicate.flags(),
+ self.flags
+ );
+ if predicate.flags().intersects(self.flags) {
+ ControlFlow::Break(FoundFlags)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+}
+
+/// Collects all the late-bound regions at the innermost binding level
+/// into a hash set.
+struct LateBoundRegionsCollector {
+ current_index: ty::DebruijnIndex,
+ regions: FxHashSet<ty::BoundRegionKind>,
+
+ /// `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: TypeVisitable<'tcx>>(
+ &mut self,
+ t: &Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ 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>) -> ControlFlow<Self::BreakTy> {
+ // 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 {
+ if let ty::Projection(..) = t.kind() {
+ return ControlFlow::CONTINUE;
+ }
+ }
+
+ t.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // if we are only looking for "constrained" region, we have to
+ // ignore the inputs of an unevaluated const, as they may not appear
+ // in the normalized form
+ if self.just_constrained {
+ if let ty::ConstKind::Unevaluated(..) = c.kind() {
+ return ControlFlow::CONTINUE;
+ }
+ }
+
+ c.super_visit_with(self)
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ReLateBound(debruijn, br) = *r {
+ if debruijn == self.current_index {
+ self.regions.insert(br.kind);
+ }
+ }
+ ControlFlow::CONTINUE
+ }
+}
+
+/// Finds the max universe present
+pub struct MaxUniverse {
+ max_universe: ty::UniverseIndex,
+}
+
+impl MaxUniverse {
+ pub fn new() -> Self {
+ MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
+ }
+
+ pub fn max_universe(self) -> ty::UniverseIndex {
+ self.max_universe
+ }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::Placeholder(placeholder) = t.kind() {
+ self.max_universe = ty::UniverseIndex::from_u32(
+ self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+ );
+ }
+
+ t.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
+ self.max_universe = ty::UniverseIndex::from_u32(
+ self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+ );
+ }
+
+ c.super_visit_with(self)
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::RePlaceholder(placeholder) = *r {
+ self.max_universe = ty::UniverseIndex::from_u32(
+ self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+ );
+ }
+
+ ControlFlow::CONTINUE
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
new file mode 100644
index 000000000..04a9fd1f7
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -0,0 +1,117 @@
+use std::convert::TryFrom;
+use std::fmt;
+
+use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit};
+use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
+use rustc_ast::Mutability;
+
+#[derive(Clone, Copy, PartialEq, HashStable)]
+pub enum VtblEntry<'tcx> {
+ /// destructor of this type (used in vtable header)
+ MetadataDropInPlace,
+ /// layout size of this type (used in vtable header)
+ MetadataSize,
+ /// layout align of this type (used in vtable header)
+ MetadataAlign,
+ /// non-dispatchable associated function that is excluded from trait object
+ Vacant,
+ /// dispatchable associated function
+ Method(Instance<'tcx>),
+ /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
+ TraitVPtr(PolyTraitRef<'tcx>),
+}
+
+impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // We want to call `Display` on `Instance` and `PolyTraitRef`,
+ // so we implement this manually.
+ match self {
+ VtblEntry::MetadataDropInPlace => write!(f, "MetadataDropInPlace"),
+ VtblEntry::MetadataSize => write!(f, "MetadataSize"),
+ VtblEntry::MetadataAlign => write!(f, "MetadataAlign"),
+ VtblEntry::Vacant => write!(f, "Vacant"),
+ VtblEntry::Method(instance) => write!(f, "Method({})", instance),
+ VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({})", trait_ref),
+ }
+ }
+}
+
+// Needs to be associated with the `'tcx` lifetime
+impl<'tcx> TyCtxt<'tcx> {
+ pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] =
+ &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+}
+
+pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
+pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
+pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
+
+/// Retrieves an allocation that represents the contents of a vtable.
+/// Since this is a query, allocations are cached and not duplicated.
+pub(super) fn vtable_allocation_provider<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
+) -> AllocId {
+ let (ty, poly_trait_ref) = key;
+
+ let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
+ let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
+ let trait_ref = tcx.erase_regions(trait_ref);
+
+ tcx.vtable_entries(trait_ref)
+ } else {
+ TyCtxt::COMMON_VTABLE_ENTRIES
+ };
+
+ let layout = tcx
+ .layout_of(ty::ParamEnv::reveal_all().and(ty))
+ .expect("failed to build vtable representation");
+ assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
+ let size = layout.size.bytes();
+ let align = layout.align.abi.bytes();
+
+ let ptr_size = tcx.data_layout.pointer_size;
+ let ptr_align = tcx.data_layout.pointer_align.abi;
+
+ let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
+ let mut vtable = Allocation::uninit(vtable_size, ptr_align, /* panic_on_fail */ true).unwrap();
+
+ // No need to do any alignment checks on the memory accesses below, because we know the
+ // allocation is correctly aligned as we created it above. Also we're only offsetting by
+ // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
+
+ for (idx, entry) in vtable_entries.iter().enumerate() {
+ let idx: u64 = u64::try_from(idx).unwrap();
+ let scalar = match entry {
+ VtblEntry::MetadataDropInPlace => {
+ let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
+ let fn_alloc_id = tcx.create_fn_alloc(instance);
+ let fn_ptr = Pointer::from(fn_alloc_id);
+ ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
+ }
+ VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
+ VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
+ VtblEntry::Vacant => continue,
+ VtblEntry::Method(instance) => {
+ // Prepare the fn ptr we write into the vtable.
+ let instance = instance.polymorphize(tcx);
+ let fn_alloc_id = tcx.create_fn_alloc(instance);
+ let fn_ptr = Pointer::from(fn_alloc_id);
+ ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
+ }
+ VtblEntry::TraitVPtr(trait_ref) => {
+ let super_trait_ref = trait_ref
+ .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+ let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref)));
+ let vptr = Pointer::from(supertrait_alloc_id);
+ ScalarMaybeUninit::from_pointer(vptr, &tcx)
+ }
+ };
+ vtable
+ .write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar)
+ .expect("failed to build vtable representation");
+ }
+
+ vtable.mutability = Mutability::Not;
+ tcx.create_memory_alloc(tcx.intern_const_alloc(vtable))
+}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
new file mode 100644
index 000000000..02fe1f3a7
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -0,0 +1,207 @@
+//! An iterator over the type substructure.
+//! WARNING: this does not keep track of the region depth.
+
+use crate::ty::subst::{GenericArg, GenericArgKind};
+use crate::ty::{self, Ty};
+use rustc_data_structures::sso::SsoHashSet;
+use smallvec::{self, SmallVec};
+
+// The TypeWalker's stack is hot enough that it's worth going to some effort to
+// avoid heap allocations.
+type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
+
+pub struct TypeWalker<'tcx> {
+ stack: TypeWalkerStack<'tcx>,
+ last_subtree: usize,
+ pub visited: SsoHashSet<GenericArg<'tcx>>,
+}
+
+/// An iterator for walking the type tree.
+///
+/// It's very easy to produce a deeply
+/// nested type tree with a lot of
+/// identical subtrees. In order to work efficiently
+/// in this situation walker only visits each type once.
+/// It maintains a set of visited types and
+/// skips any types that are already there.
+impl<'tcx> TypeWalker<'tcx> {
+ pub fn new(root: GenericArg<'tcx>) -> Self {
+ Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
+ }
+
+ /// Skips the subtree corresponding to the last type
+ /// returned by `next()`.
+ ///
+ /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
+ ///
+ /// ```ignore (illustrative)
+ /// let mut iter: TypeWalker = ...;
+ /// iter.next(); // yields Foo
+ /// iter.next(); // yields Bar<i32>
+ /// iter.skip_current_subtree(); // skips i32
+ /// 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 = GenericArg<'tcx>;
+
+ fn next(&mut self) -> Option<GenericArg<'tcx>> {
+ debug!("next(): stack={:?}", self.stack);
+ loop {
+ let next = self.stack.pop()?;
+ self.last_subtree = self.stack.len();
+ if self.visited.insert(next) {
+ push_inner(&mut self.stack, next);
+ debug!("next: stack={:?}", self.stack);
+ return Some(next);
+ }
+ }
+ }
+}
+
+impl<'tcx> GenericArg<'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:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(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`).
+ ///
+ /// Iterator only walks items once.
+ /// It accepts visited set, updates it with all visited types
+ /// and skips any types that are already there.
+ pub fn walk_shallow(
+ self,
+ visited: &mut SsoHashSet<GenericArg<'tcx>>,
+ ) -> impl Iterator<Item = GenericArg<'tcx>> {
+ let mut stack = SmallVec::new();
+ push_inner(&mut stack, self);
+ stack.retain(|a| visited.insert(*a));
+ stack.into_iter()
+ }
+}
+
+impl<'tcx> Ty<'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:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(self) -> TypeWalker<'tcx> {
+ TypeWalker::new(self.into())
+ }
+}
+
+/// We push `GenericArg`s 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_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
+ match parent.unpack() {
+ GenericArgKind::Type(parent_ty) => 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) => {
+ stack.push(len.into());
+ stack.push(ty.into());
+ }
+ ty::Slice(ty) => {
+ stack.push(ty.into());
+ }
+ ty::RawPtr(mt) => {
+ stack.push(mt.ty.into());
+ }
+ ty::Ref(lt, ty, _) => {
+ stack.push(ty.into());
+ stack.push(lt.into());
+ }
+ ty::Projection(data) => {
+ stack.extend(data.substs.iter().rev());
+ }
+ ty::Dynamic(obj, lt) => {
+ stack.push(lt.into());
+ 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.term)),
+ ty::ExistentialPredicate::AutoTrait(_) =>
+ // Empty iterator
+ {
+ (ty::InternalSubsts::empty(), None)
+ }
+ };
+
+ substs.iter().rev().chain(opt_ty.map(|term| match term {
+ ty::Term::Ty(ty) => ty.into(),
+ ty::Term::Const(ct) => ct.into(),
+ }))
+ }));
+ }
+ ty::Adt(_, substs)
+ | ty::Opaque(_, substs)
+ | ty::Closure(_, substs)
+ | ty::Generator(_, substs, _)
+ | ty::FnDef(_, substs) => {
+ stack.extend(substs.iter().rev());
+ }
+ ty::Tuple(ts) => stack.extend(ts.as_substs().iter().rev()),
+ ty::GeneratorWitness(ts) => {
+ stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into()));
+ }
+ ty::FnPtr(sig) => {
+ stack.push(sig.skip_binder().output().into());
+ stack.extend(sig.skip_binder().inputs().iter().copied().rev().map(|ty| ty.into()));
+ }
+ },
+ GenericArgKind::Lifetime(_) => {}
+ GenericArgKind::Const(parent_ct) => {
+ stack.push(parent_ct.ty().into());
+ match parent_ct.kind() {
+ ty::ConstKind::Infer(_)
+ | ty::ConstKind::Param(_)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Value(_)
+ | ty::ConstKind::Error(_) => {}
+
+ ty::ConstKind::Unevaluated(ct) => {
+ stack.extend(ct.substs.iter().rev());
+ }
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
new file mode 100644
index 000000000..fd7045d6a
--- /dev/null
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -0,0 +1,54 @@
+// These functions are used by macro expansion for bug! and span_bug!
+
+use crate::ty::{tls, TyCtxt};
+use rustc_errors::MultiSpan;
+use rustc_span::Span;
+use std::fmt;
+use std::panic::{panic_any, Location};
+
+#[cold]
+#[inline(never)]
+#[track_caller]
+pub fn bug_fmt(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(None::<Span>, args, Location::caller());
+}
+
+#[cold]
+#[inline(never)]
+#[track_caller]
+pub fn span_bug_fmt<S: Into<MultiSpan>>(span: S, args: fmt::Arguments<'_>) -> ! {
+ opt_span_bug_fmt(Some(span), args, Location::caller());
+}
+
+#[track_caller]
+fn opt_span_bug_fmt<S: Into<MultiSpan>>(
+ span: Option<S>,
+ args: fmt::Arguments<'_>,
+ location: &Location<'_>,
+) -> ! {
+ tls::with_opt(move |tcx| {
+ let msg = format!("{}: {}", location, 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_any(msg),
+ }
+ });
+ unreachable!();
+}
+
+/// A query to trigger a `delay_span_bug`. Clearly, if one has a `tcx` one can already trigger a
+/// `delay_span_bug`, so what is the point of this? It exists to help us test `delay_span_bug`'s
+/// interactions with the query system and incremental.
+pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(key),
+ "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]",
+ );
+}
+
+pub fn provide(providers: &mut crate::ty::query::Providers) {
+ *providers = crate::ty::query::Providers { trigger_delay_span_bug, ..*providers };
+}
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
new file mode 100644
index 000000000..08977049d
--- /dev/null
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -0,0 +1,67 @@
+use rustc_data_structures::sync::Lock;
+
+use std::fmt::Debug;
+use std::time::{Duration, Instant};
+
+#[cfg(test)]
+mod tests;
+
+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 += 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/compiler/rustc_middle/src/util/common/tests.rs b/compiler/rustc_middle/src/util/common/tests.rs
new file mode 100644
index 000000000..9a9fb203c
--- /dev/null
+++ b/compiler/rustc_middle/src/util/common/tests.rs
@@ -0,0 +1,14 @@
+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));
+}