1 //! THIR datatypes and definitions. See the [rustc dev guide] for more info.
3 //! If you compare the THIR [`ExprKind`] to [`hir::ExprKind`], you will see it is
4 //! a good bit simpler. In fact, a number of the more straight-forward
5 //! MIR simplifications are already done in the lowering to THIR. For
6 //! example, method calls and overloaded operators are absent: they are
7 //! expected to be converted into [`ExprKind::Call`] instances.
9 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
11 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
13 use rustc_hir::def::CtorKind;
14 use rustc_hir::def_id::DefId;
15 use rustc_hir::RangeEnd;
16 use rustc_index::newtype_index;
17 use rustc_index::vec::IndexVec;
18 use rustc_middle::infer::canonical::Canonical;
19 use rustc_middle::middle::region;
20 use rustc_middle::mir::{
21 BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
23 use rustc_middle::ty::adjustment::PointerCast;
24 use rustc_middle::ty::subst::SubstsRef;
25 use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
26 use rustc_middle::ty::{
27 CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
29 use rustc_span::{Span, Symbol, DUMMY_SP};
30 use rustc_target::abi::VariantIdx;
31 use rustc_target::asm::InlineAsmRegOrRegClass;
37 /// An index to an [`Arm`] stored in [`Thir::arms`]
45 /// An index to an [`Expr`] stored in [`Thir::exprs`]
54 /// An index to a [`Stmt`] stored in [`Thir::stmts`]
60 macro_rules! thir_with_elements {
61 ($($name:ident: $id:ty => $value:ty,)*) => {
62 /// A container for a THIR body.
64 /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
65 #[derive(Debug, HashStable)]
66 pub struct Thir<'tcx> {
68 pub $name: IndexVec<$id, $value>,
72 impl<'tcx> Thir<'tcx> {
73 pub fn new() -> Thir<'tcx> {
76 $name: IndexVec::new(),
83 impl<'tcx> Index<$id> for Thir<'tcx> {
85 fn index(&self, index: $id) -> &Self::Output {
94 arms: ArmId => Arm<'tcx>,
95 exprs: ExprId => Expr<'tcx>,
96 stmts: StmtId => Stmt<'tcx>,
99 #[derive(Copy, Clone, Debug, HashStable)]
102 Explicit(hir::HirId),
105 #[derive(Debug, HashStable)]
107 /// Whether the block itself has a label. Used by `label: {}`
108 /// and `try` blocks.
110 /// This does *not* include labels on loops, e.g. `'label: loop {}`.
111 pub targeted_by_break: bool,
112 pub region_scope: region::Scope,
113 pub opt_destruction_scope: Option<region::Scope>,
114 /// The span of the block, including the opening braces,
115 /// the label, and the `unsafe` keyword, if present.
117 /// The statements in the blocK.
118 pub stmts: Box<[StmtId]>,
119 /// The trailing expression of the block, if any.
120 pub expr: Option<ExprId>,
121 pub safety_mode: BlockSafety,
124 #[derive(Debug, HashStable)]
125 pub struct Adt<'tcx> {
126 /// The ADT we're constructing.
127 pub adt_def: &'tcx AdtDef,
128 /// The variant of the ADT.
129 pub variant_index: VariantIdx,
130 pub substs: SubstsRef<'tcx>,
132 /// Optional user-given substs: for something like `let x =
133 /// Bar::<T> { ... }`.
134 pub user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
136 pub fields: Box<[FieldExpr]>,
137 /// The base, e.g. `Foo {x: 1, .. base}`.
138 pub base: Option<FruInfo<'tcx>>,
141 #[derive(Copy, Clone, Debug, HashStable)]
142 pub enum BlockSafety {
144 /// A compiler-generated unsafe block
146 /// An `unsafe` block. The `HirId` is the ID of the block.
147 ExplicitUnsafe(hir::HirId),
150 #[derive(Debug, HashStable)]
151 pub struct Stmt<'tcx> {
152 pub kind: StmtKind<'tcx>,
153 pub opt_destruction_scope: Option<region::Scope>,
156 #[derive(Debug, HashStable)]
157 pub enum StmtKind<'tcx> {
158 /// An expression with a trailing semicolon.
160 /// The scope for this statement; may be used as lifetime of temporaries.
161 scope: region::Scope,
163 /// The expression being evaluated in this statement.
169 /// The scope for variables bound in this `let`; it covers this and
170 /// all the remaining statements in the block.
171 remainder_scope: region::Scope,
173 /// The scope for the initialization itself; might be used as
174 /// lifetime of temporaries.
175 init_scope: region::Scope,
177 /// `let <PAT> = ...`
179 /// If a type annotation is included, it is added as an ascription pattern.
182 /// `let pat: ty = <INIT>`
183 initializer: Option<ExprId>,
185 /// The lint level for this `let` statement.
186 lint_level: LintLevel,
190 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
191 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
192 rustc_data_structures::static_assert_size!(Expr<'_>, 104);
194 /// A THIR expression.
195 #[derive(Debug, HashStable)]
196 pub struct Expr<'tcx> {
197 /// The type of this expression
200 /// The lifetime of this expression if it should be spilled into a
201 /// temporary; should be `None` only if in a constant context
202 pub temp_lifetime: Option<region::Scope>,
204 /// span of the expression in the source
207 /// kind of expression
208 pub kind: ExprKind<'tcx>,
211 #[derive(Debug, HashStable)]
212 pub enum ExprKind<'tcx> {
213 /// `Scope`s are used to explicitely mark destruction scopes,
214 /// and to track the `HirId` of the expressions within the scope.
216 region_scope: region::Scope,
217 lint_level: LintLevel,
220 /// A `box <value>` expression.
224 /// An `if` expression.
226 if_then_scope: region::Scope,
229 else_opt: Option<ExprId>,
231 /// A function call. Method calls and overloaded operators are converted to plain function calls.
233 /// The type of the function. This is often a [`FnDef`] or a [`FnPtr`].
235 /// [`FnDef`]: ty::TyKind::FnDef
236 /// [`FnPtr`]: ty::TyKind::FnPtr
238 /// The function itself.
240 /// The arguments passed to the function.
242 /// Note: in some cases (like calling a closure), the function call `f(...args)` gets
243 /// rewritten as a call to a function trait method (e.g. `FnOnce::call_once(f, (...args))`).
245 /// Whether this is from an overloaded operator rather than a
246 /// function call from HIR. `true` for overloaded function call.
248 /// The span of the function, without the dot and receiver
249 /// (e.g. `foo(a, b)` in `x.foo(a, b)`).
252 /// A *non-overloaded* dereference.
256 /// A *non-overloaded* binary operation.
262 /// A logical operation. This is distinct from `BinaryOp` because
263 /// the operands need to be lazily evaluated.
269 /// A *non-overloaded* unary operation. Note that here the deref (`*`)
270 /// operator is represented by `ExprKind::Deref`.
275 /// A cast: `<source> as <type>`. The type we cast to is the type of
276 /// the parent expression.
282 }, // Use a lexpr to get a vexpr.
283 /// A coercion from `!` to any type.
287 /// A pointer cast. More information can be found in [`PointerCast`].
292 /// A `loop` expression.
300 /// A `match` expression.
309 /// An assignment: `lhs = rhs`.
314 /// A *non-overloaded* operation assignment, e.g. `lhs += rhs`.
320 /// Access to a struct or tuple field.
323 /// This can be a named (`.foo`) or unnamed (`.0`) field.
326 /// A *non-overloaded* indexing operation.
331 /// A local variable.
335 /// Used to represent upvars mentioned in a closure/generator
337 /// DefId of the closure/generator
338 closure_def_id: DefId,
340 /// HirId of the root variable
341 var_hir_id: hir::HirId,
343 /// A borrow, e.g. `&arg`.
345 borrow_kind: BorrowKind,
348 /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
350 mutability: hir::Mutability,
353 /// A `break` expression.
355 label: region::Scope,
356 value: Option<ExprId>,
358 /// A `continue` expression.
360 label: region::Scope,
362 /// A `return` expression.
364 value: Option<ExprId>,
366 /// An inline `const` block, e.g. `const {}`.
368 value: &'tcx Const<'tcx>,
370 /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
373 count: &'tcx Const<'tcx>,
375 /// An array, e.g. `[a, b, c, d]`.
377 fields: Box<[ExprId]>,
379 /// A tuple, e.g. `(a, b, c, d)`.
381 fields: Box<[ExprId]>,
383 /// An ADT constructor, e.g. `Foo {x: 1, y: 2}`.
385 /// A type ascription on a place.
386 PlaceTypeAscription {
388 /// Type that the user gave to this expression
389 user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
391 /// A type ascription on a value, e.g. `42: i32`.
392 ValueTypeAscription {
394 /// Type that the user gave to this expression
395 user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
397 /// A closure definition.
400 substs: UpvarSubsts<'tcx>,
401 upvars: Box<[ExprId]>,
402 movability: Option<hir::Movability>,
403 fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
407 literal: &'tcx Const<'tcx>,
408 user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
409 /// The `DefId` of the `const` item this literal
410 /// was produced from, if this is not a user-written
412 const_id: Option<DefId>,
414 /// A literal containing the address of a `static`.
416 /// This is only distinguished from `Literal` so that we can register some
417 /// info for diagnostics.
419 literal: &'tcx Const<'tcx>,
422 /// Inline assembly, i.e. `asm!()`.
424 template: &'tcx [InlineAsmTemplatePiece],
425 operands: Box<[InlineAsmOperand<'tcx>]>,
426 options: InlineAsmOptions,
427 line_spans: &'tcx [Span],
429 /// An expression taking a reference to a thread local.
430 ThreadLocalRef(DefId),
431 /// Inline LLVM assembly, i.e. `llvm_asm!()`.
433 asm: &'tcx hir::LlvmInlineAsmInner,
434 outputs: Box<[ExprId]>,
435 inputs: Box<[ExprId]>,
437 /// A `yield` expression.
443 /// Represents the association of a field identifier and an expression.
445 /// This is used in struct constructors.
446 #[derive(Debug, HashStable)]
447 pub struct FieldExpr {
452 #[derive(Debug, HashStable)]
453 pub struct FruInfo<'tcx> {
455 pub field_types: Box<[Ty<'tcx>]>,
459 #[derive(Debug, HashStable)]
460 pub struct Arm<'tcx> {
461 pub pattern: Pat<'tcx>,
462 pub guard: Option<Guard<'tcx>>,
464 pub lint_level: LintLevel,
465 pub scope: region::Scope,
470 #[derive(Debug, HashStable)]
471 pub enum Guard<'tcx> {
473 IfLet(Pat<'tcx>, ExprId),
476 #[derive(Copy, Clone, Debug, HashStable)]
478 /// The `&&` operator.
480 /// The `||` operator.
484 #[derive(Debug, HashStable)]
485 pub enum InlineAsmOperand<'tcx> {
487 reg: InlineAsmRegOrRegClass,
491 reg: InlineAsmRegOrRegClass,
493 expr: Option<ExprId>,
496 reg: InlineAsmRegOrRegClass,
501 reg: InlineAsmRegOrRegClass,
504 out_expr: Option<ExprId>,
507 value: &'tcx Const<'tcx>,
518 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
519 pub enum BindingMode {
524 #[derive(Clone, Debug, PartialEq, HashStable)]
525 pub struct FieldPat<'tcx> {
527 pub pattern: Pat<'tcx>,
530 #[derive(Clone, Debug, PartialEq, HashStable)]
531 pub struct Pat<'tcx> {
534 pub kind: Box<PatKind<'tcx>>,
537 impl<'tcx> Pat<'tcx> {
538 pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
539 Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
543 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
544 pub struct PatTyProj<'tcx> {
545 pub user_ty: CanonicalUserType<'tcx>,
548 impl<'tcx> PatTyProj<'tcx> {
549 pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
550 Self { user_ty: user_annotation }
555 annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
556 inferred_ty: Ty<'tcx>,
558 ) -> UserTypeProjection {
560 base: annotations.push(CanonicalUserTypeAnnotation {
562 user_ty: self.user_ty,
570 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
571 pub struct Ascription<'tcx> {
572 pub user_ty: PatTyProj<'tcx>,
573 /// Variance to use when relating the type `user_ty` to the **type of the value being
574 /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
575 /// have a type that is some subtype of the ascribed type.
577 /// Note that this variance does not apply for any bindings within subpatterns. The type
578 /// assigned to those bindings must be exactly equal to the `user_ty` given here.
580 /// The only place where this field is not `Covariant` is when matching constants, where
581 /// we currently use `Contravariant` -- this is because the constant type just needs to
582 /// be "comparable" to the type of the input value. So, for example:
585 /// match x { "foo" => .. }
588 /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
589 /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
590 /// of the old type-check for now. See #57280 for details.
591 pub variance: ty::Variance,
592 pub user_ty_span: Span,
595 #[derive(Clone, Debug, PartialEq, HashStable)]
596 pub enum PatKind<'tcx> {
597 /// A wildward pattern: `_`.
601 ascription: Ascription<'tcx>,
602 subpattern: Pat<'tcx>,
605 /// `x`, `ref x`, `x @ P`, etc.
607 mutability: Mutability,
612 subpattern: Option<Pat<'tcx>>,
613 /// Is this the leftmost occurrence of the binding, i.e., is `var` the
614 /// `HirId` of this pattern?
618 /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
619 /// multiple variants.
621 adt_def: &'tcx AdtDef,
622 substs: SubstsRef<'tcx>,
623 variant_index: VariantIdx,
624 subpatterns: Vec<FieldPat<'tcx>>,
627 /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
628 /// a single variant.
630 subpatterns: Vec<FieldPat<'tcx>>,
633 /// `box P`, `&P`, `&mut P`, etc.
635 subpattern: Pat<'tcx>,
638 /// One of the following:
639 /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
640 /// checking will detect if you use the same string twice in different patterns.
641 /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
642 /// its own value, similar to `&str`, but these values are much simpler.
643 /// * Opaque constants, that must not be matched structurally. So anything that does not derive
644 /// `PartialEq` and `Eq`.
646 value: &'tcx ty::Const<'tcx>,
649 Range(PatRange<'tcx>),
651 /// Matches against a slice, checking the length and extracting elements.
652 /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
653 /// e.g., `&[ref xs @ ..]`.
655 prefix: Vec<Pat<'tcx>>,
656 slice: Option<Pat<'tcx>>,
657 suffix: Vec<Pat<'tcx>>,
660 /// Fixed match against an array; irrefutable.
662 prefix: Vec<Pat<'tcx>>,
663 slice: Option<Pat<'tcx>>,
664 suffix: Vec<Pat<'tcx>>,
667 /// An or-pattern, e.g. `p | q`.
668 /// Invariant: `pats.len() >= 2`.
670 pats: Vec<Pat<'tcx>>,
674 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
675 pub struct PatRange<'tcx> {
676 pub lo: &'tcx ty::Const<'tcx>,
677 pub hi: &'tcx ty::Const<'tcx>,
681 impl<'tcx> fmt::Display for Pat<'tcx> {
682 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683 // Printing lists is a chore.
684 let mut first = true;
685 let mut start_or_continue = |s| {
693 let mut start_or_comma = || start_or_continue(", ");
696 PatKind::Wild => write!(f, "_"),
697 PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
698 PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
699 let is_mut = match mode {
700 BindingMode::ByValue => mutability == Mutability::Mut,
701 BindingMode::ByRef(bk) => {
703 matches!(bk, BorrowKind::Mut { .. })
709 write!(f, "{}", name)?;
710 if let Some(ref subpattern) = *subpattern {
711 write!(f, " @ {}", subpattern)?;
715 PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
716 let variant = match *self.kind {
717 PatKind::Variant { adt_def, variant_index, .. } => {
718 Some(&adt_def.variants[variant_index])
720 _ => self.ty.ty_adt_def().and_then(|adt| {
721 if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None }
725 if let Some(variant) = variant {
726 write!(f, "{}", variant.ident)?;
728 // Only for Adt we can have `S {...}`,
729 // which we handle separately here.
730 if variant.ctor_kind == CtorKind::Fictive {
734 for p in subpatterns {
735 if let PatKind::Wild = *p.pattern.kind {
738 let name = variant.fields[p.field.index()].ident;
739 write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
743 if printed < variant.fields.len() {
744 write!(f, "{}..", start_or_comma())?;
747 return write!(f, " }}");
751 let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
752 if num_fields != 0 || variant.is_none() {
754 for i in 0..num_fields {
755 write!(f, "{}", start_or_comma())?;
757 // Common case: the field is where we expect it.
758 if let Some(p) = subpatterns.get(i) {
759 if p.field.index() == i {
760 write!(f, "{}", p.pattern)?;
765 // Otherwise, we have to go looking for it.
766 if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
767 write!(f, "{}", p.pattern)?;
777 PatKind::Deref { ref subpattern } => {
778 match self.ty.kind() {
779 ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
780 ty::Ref(_, _, mutbl) => {
781 write!(f, "&{}", mutbl.prefix_str())?;
783 _ => bug!("{} is a bad Deref pattern type", self.ty),
785 write!(f, "{}", subpattern)
787 PatKind::Constant { value } => write!(f, "{}", value),
788 PatKind::Range(PatRange { lo, hi, end }) => {
789 write!(f, "{}", lo)?;
790 write!(f, "{}", end)?;
793 PatKind::Slice { ref prefix, ref slice, ref suffix }
794 | PatKind::Array { ref prefix, ref slice, ref suffix } => {
797 write!(f, "{}{}", start_or_comma(), p)?;
799 if let Some(ref slice) = *slice {
800 write!(f, "{}", start_or_comma())?;
803 _ => write!(f, "{}", slice)?,
808 write!(f, "{}{}", start_or_comma(), p)?;
812 PatKind::Or { ref pats } => {
814 write!(f, "{}{}", start_or_continue(" | "), pat)?;
824 pub trait Visitor<'a, 'tcx: 'a>: Sized {
825 fn thir(&self) -> &'a Thir<'tcx>;
827 fn visit_expr(&mut self, expr: &Expr<'tcx>) {
828 walk_expr(self, expr);
831 fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
832 walk_stmt(self, stmt);
835 fn visit_block(&mut self, block: &Block) {
836 walk_block(self, block);
839 fn visit_arm(&mut self, arm: &Arm<'tcx>) {
843 fn visit_pat(&mut self, pat: &Pat<'tcx>) {
847 fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
850 pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
853 Scope { value, region_scope: _, lint_level: _ } => {
854 visitor.visit_expr(&visitor.thir()[value])
856 Box { value } => visitor.visit_expr(&visitor.thir()[value]),
857 If { cond, then, else_opt, if_then_scope: _ } => {
858 visitor.visit_expr(&visitor.thir()[cond]);
859 visitor.visit_expr(&visitor.thir()[then]);
860 if let Some(else_expr) = else_opt {
861 visitor.visit_expr(&visitor.thir()[else_expr]);
864 Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
865 visitor.visit_expr(&visitor.thir()[fun]);
866 for &arg in &**args {
867 visitor.visit_expr(&visitor.thir()[arg]);
870 Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
871 Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
872 visitor.visit_expr(&visitor.thir()[lhs]);
873 visitor.visit_expr(&visitor.thir()[rhs]);
875 Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
876 Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
877 Use { source } => visitor.visit_expr(&visitor.thir()[source]),
878 NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
879 Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
880 Let { expr, .. } => {
881 visitor.visit_expr(&visitor.thir()[expr]);
883 Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
884 Match { scrutinee, ref arms } => {
885 visitor.visit_expr(&visitor.thir()[scrutinee]);
886 for &arm in &**arms {
887 visitor.visit_arm(&visitor.thir()[arm]);
890 Block { ref body } => visitor.visit_block(body),
891 Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
892 visitor.visit_expr(&visitor.thir()[lhs]);
893 visitor.visit_expr(&visitor.thir()[rhs]);
895 Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
896 Index { lhs, index } => {
897 visitor.visit_expr(&visitor.thir()[lhs]);
898 visitor.visit_expr(&visitor.thir()[index]);
900 VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
901 Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
902 AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
903 Break { value, label: _ } => {
904 if let Some(value) = value {
905 visitor.visit_expr(&visitor.thir()[value])
908 Continue { label: _ } => {}
909 Return { value } => {
910 if let Some(value) = value {
911 visitor.visit_expr(&visitor.thir()[value])
914 ConstBlock { value } => visitor.visit_const(value),
915 Repeat { value, count } => {
916 visitor.visit_expr(&visitor.thir()[value]);
917 visitor.visit_const(count);
919 Array { ref fields } | Tuple { ref fields } => {
920 for &field in &**fields {
921 visitor.visit_expr(&visitor.thir()[field]);
924 Adt(box crate::thir::Adt {
932 for field in &**fields {
933 visitor.visit_expr(&visitor.thir()[field.expr]);
935 if let Some(base) = base {
936 visitor.visit_expr(&visitor.thir()[base.base]);
939 PlaceTypeAscription { source, user_ty: _ }
940 | ValueTypeAscription { source, user_ty: _ } => {
941 visitor.visit_expr(&visitor.thir()[source])
943 Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
944 Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
945 StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
946 InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
947 for op in &**operands {
948 use InlineAsmOperand::*;
951 | Out { expr: Some(expr), reg: _, late: _ }
952 | InOut { expr, reg: _, late: _ }
953 | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
954 SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
955 visitor.visit_expr(&visitor.thir()[*in_expr]);
956 if let Some(out_expr) = out_expr {
957 visitor.visit_expr(&visitor.thir()[*out_expr]);
960 Out { expr: None, reg: _, late: _ }
961 | Const { value: _, span: _ }
962 | SymStatic { def_id: _ } => {}
966 ThreadLocalRef(_) => {}
967 LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
968 for &out_expr in &**outputs {
969 visitor.visit_expr(&visitor.thir()[out_expr]);
971 for &in_expr in &**inputs {
972 visitor.visit_expr(&visitor.thir()[in_expr]);
975 Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
979 pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
981 StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
989 if let Some(init) = initializer {
990 visitor.visit_expr(&visitor.thir()[*init]);
992 visitor.visit_pat(pattern);
997 pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
998 for &stmt in &*block.stmts {
999 visitor.visit_stmt(&visitor.thir()[stmt]);
1001 if let Some(expr) = block.expr {
1002 visitor.visit_expr(&visitor.thir()[expr]);
1006 pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
1008 Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
1009 Some(Guard::IfLet(ref pat, expr)) => {
1010 visitor.visit_pat(pat);
1011 visitor.visit_expr(&visitor.thir()[expr]);
1015 visitor.visit_pat(&arm.pattern);
1016 visitor.visit_expr(&visitor.thir()[arm.body]);
1019 pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
1021 match pat.kind.as_ref() {
1022 AscribeUserType { subpattern, ascription: _ }
1023 | Deref { subpattern }
1025 subpattern: Some(subpattern),
1032 } => visitor.visit_pat(&subpattern),
1033 Binding { .. } | Wild => {}
1034 Variant { subpatterns, adt_def: _, substs: _, variant_index: _ }
1035 | Leaf { subpatterns } => {
1036 for subpattern in subpatterns {
1037 visitor.visit_pat(&subpattern.pattern);
1040 Constant { value } => visitor.visit_const(value),
1042 visitor.visit_const(range.lo);
1043 visitor.visit_const(range.hi);
1045 Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
1046 for subpattern in prefix {
1047 visitor.visit_pat(&subpattern);
1049 if let Some(pat) = slice {
1050 visitor.visit_pat(pat);
1052 for subpattern in suffix {
1053 visitor.visit_pat(&subpattern);
1058 visitor.visit_pat(&pat);