rustc_middle/thir.rs
1//! THIR datatypes and definitions. See the [rustc dev guide] for more info.
2//!
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.
8//!
9//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
10
11use std::cmp::Ordering;
12use std::fmt;
13use std::ops::Index;
14use std::sync::Arc;
15
16use rustc_abi::{FieldIdx, Integer, Size, VariantIdx};
17use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
18use rustc_hir as hir;
19use rustc_hir::def_id::DefId;
20use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
21use rustc_index::{IndexVec, newtype_index};
22use rustc_macros::{HashStable, TypeVisitable};
23use rustc_span::def_id::LocalDefId;
24use rustc_span::{ErrorGuaranteed, Span, Symbol};
25use rustc_target::asm::InlineAsmRegOrRegClass;
26use tracing::instrument;
27
28use crate::middle::region;
29use crate::mir::interpret::AllocId;
30use crate::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
31use crate::ty::adjustment::PointerCoercion;
32use crate::ty::layout::IntegerExt;
33use crate::ty::{
34 self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty,
35 TyCtxt, UpvarArgs,
36};
37
38pub mod visit;
39
40macro_rules! thir_with_elements {
41 (
42 $($name:ident: $id:ty => $value:ty => $format:literal,)*
43 ) => {
44 $(
45 newtype_index! {
46 #[derive(HashStable)]
47 #[debug_format = $format]
48 pub struct $id {}
49 }
50 )*
51
52 /// A container for a THIR body.
53 ///
54 /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
55 #[derive(Debug, HashStable)]
56 pub struct Thir<'tcx> {
57 pub body_type: BodyTy<'tcx>,
58 $(
59 pub $name: IndexVec<$id, $value>,
60 )*
61 }
62
63 impl<'tcx> Thir<'tcx> {
64 pub fn new(body_type: BodyTy<'tcx>) -> Thir<'tcx> {
65 Thir {
66 body_type,
67 $(
68 $name: IndexVec::new(),
69 )*
70 }
71 }
72 }
73
74 $(
75 impl<'tcx> Index<$id> for Thir<'tcx> {
76 type Output = $value;
77 fn index(&self, index: $id) -> &Self::Output {
78 &self.$name[index]
79 }
80 }
81 )*
82 }
83}
84
85thir_with_elements! {
86 arms: ArmId => Arm<'tcx> => "a{}",
87 blocks: BlockId => Block => "b{}",
88 exprs: ExprId => Expr<'tcx> => "e{}",
89 stmts: StmtId => Stmt<'tcx> => "s{}",
90 params: ParamId => Param<'tcx> => "p{}",
91}
92
93#[derive(Debug, HashStable)]
94pub enum BodyTy<'tcx> {
95 Const(Ty<'tcx>),
96 Fn(FnSig<'tcx>),
97}
98
99/// Description of a type-checked function parameter.
100#[derive(Debug, HashStable)]
101pub struct Param<'tcx> {
102 /// The pattern that appears in the parameter list, or None for implicit parameters.
103 pub pat: Option<Box<Pat<'tcx>>>,
104 /// The possibly inferred type.
105 pub ty: Ty<'tcx>,
106 /// Span of the explicitly provided type, or None if inferred for closures.
107 pub ty_span: Option<Span>,
108 /// Whether this param is `self`, and how it is bound.
109 pub self_kind: Option<hir::ImplicitSelfKind>,
110 /// HirId for lints.
111 pub hir_id: Option<HirId>,
112}
113
114#[derive(Copy, Clone, Debug, HashStable)]
115pub enum LintLevel {
116 Inherited,
117 Explicit(HirId),
118}
119
120#[derive(Debug, HashStable)]
121pub struct Block {
122 /// Whether the block itself has a label. Used by `label: {}`
123 /// and `try` blocks.
124 ///
125 /// This does *not* include labels on loops, e.g. `'label: loop {}`.
126 pub targeted_by_break: bool,
127 pub region_scope: region::Scope,
128 /// The span of the block, including the opening braces,
129 /// the label, and the `unsafe` keyword, if present.
130 pub span: Span,
131 /// The statements in the blocK.
132 pub stmts: Box<[StmtId]>,
133 /// The trailing expression of the block, if any.
134 pub expr: Option<ExprId>,
135 pub safety_mode: BlockSafety,
136}
137
138type UserTy<'tcx> = Option<Box<CanonicalUserType<'tcx>>>;
139
140#[derive(Debug, HashStable)]
141pub struct AdtExpr<'tcx> {
142 /// The ADT we're constructing.
143 pub adt_def: AdtDef<'tcx>,
144 /// The variant of the ADT.
145 pub variant_index: VariantIdx,
146 pub args: GenericArgsRef<'tcx>,
147
148 /// Optional user-given args: for something like `let x =
149 /// Bar::<T> { ... }`.
150 pub user_ty: UserTy<'tcx>,
151
152 pub fields: Box<[FieldExpr]>,
153 /// The base, e.g. `Foo {x: 1, ..base}`.
154 pub base: AdtExprBase<'tcx>,
155}
156
157#[derive(Debug, HashStable)]
158pub enum AdtExprBase<'tcx> {
159 /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`.
160 None,
161 /// A struct expression with a "base", an expression of the same type as the outer struct that
162 /// will be used to populate any fields not explicitly mentioned: `Foo { ..base }`
163 Base(FruInfo<'tcx>),
164 /// A struct expression with a `..` tail but no "base" expression. The values from the struct
165 /// fields' default values will be used to populate any fields not explicitly mentioned:
166 /// `Foo { .. }`.
167 DefaultFields(Box<[Ty<'tcx>]>),
168}
169
170#[derive(Debug, HashStable)]
171pub struct ClosureExpr<'tcx> {
172 pub closure_id: LocalDefId,
173 pub args: UpvarArgs<'tcx>,
174 pub upvars: Box<[ExprId]>,
175 pub movability: Option<hir::Movability>,
176 pub fake_reads: Vec<(ExprId, FakeReadCause, HirId)>,
177}
178
179#[derive(Debug, HashStable)]
180pub struct InlineAsmExpr<'tcx> {
181 pub asm_macro: AsmMacro,
182 pub template: &'tcx [InlineAsmTemplatePiece],
183 pub operands: Box<[InlineAsmOperand<'tcx>]>,
184 pub options: InlineAsmOptions,
185 pub line_spans: &'tcx [Span],
186}
187
188#[derive(Copy, Clone, Debug, HashStable)]
189pub enum BlockSafety {
190 Safe,
191 /// A compiler-generated unsafe block
192 BuiltinUnsafe,
193 /// An `unsafe` block. The `HirId` is the ID of the block.
194 ExplicitUnsafe(HirId),
195}
196
197#[derive(Debug, HashStable)]
198pub struct Stmt<'tcx> {
199 pub kind: StmtKind<'tcx>,
200}
201
202#[derive(Debug, HashStable)]
203pub enum StmtKind<'tcx> {
204 /// An expression with a trailing semicolon.
205 Expr {
206 /// The scope for this statement; may be used as lifetime of temporaries.
207 scope: region::Scope,
208
209 /// The expression being evaluated in this statement.
210 expr: ExprId,
211 },
212
213 /// A `let` binding.
214 Let {
215 /// The scope for variables bound in this `let`; it covers this and
216 /// all the remaining statements in the block.
217 remainder_scope: region::Scope,
218
219 /// The scope for the initialization itself; might be used as
220 /// lifetime of temporaries.
221 init_scope: region::Scope,
222
223 /// `let <PAT> = ...`
224 ///
225 /// If a type annotation is included, it is added as an ascription pattern.
226 pattern: Box<Pat<'tcx>>,
227
228 /// `let pat: ty = <INIT>`
229 initializer: Option<ExprId>,
230
231 /// `let pat: ty = <INIT> else { <ELSE> }`
232 else_block: Option<BlockId>,
233
234 /// The lint level for this `let` statement.
235 lint_level: LintLevel,
236
237 /// Span of the `let <PAT> = <INIT>` part.
238 span: Span,
239 },
240}
241
242#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, HashStable)]
243pub struct LocalVarId(pub HirId);
244
245/// A THIR expression.
246#[derive(Debug, HashStable)]
247pub struct Expr<'tcx> {
248 /// kind of expression
249 pub kind: ExprKind<'tcx>,
250
251 /// The type of this expression
252 pub ty: Ty<'tcx>,
253
254 /// The lifetime of this expression if it should be spilled into a
255 /// temporary
256 pub temp_lifetime: TempLifetime,
257
258 /// span of the expression in the source
259 pub span: Span,
260}
261
262/// Temporary lifetime information for THIR expressions
263#[derive(Clone, Copy, Debug, HashStable)]
264pub struct TempLifetime {
265 /// Lifetime for temporaries as expected.
266 /// This should be `None` in a constant context.
267 pub temp_lifetime: Option<region::Scope>,
268 /// If `Some(lt)`, indicates that the lifetime of this temporary will change to `lt` in a future edition.
269 /// If `None`, then no changes are expected, or lints are disabled.
270 pub backwards_incompatible: Option<region::Scope>,
271}
272
273#[derive(Debug, HashStable)]
274pub enum ExprKind<'tcx> {
275 /// `Scope`s are used to explicitly mark destruction scopes,
276 /// and to track the `HirId` of the expressions within the scope.
277 Scope {
278 region_scope: region::Scope,
279 lint_level: LintLevel,
280 value: ExprId,
281 },
282 /// A `box <value>` expression.
283 Box {
284 value: ExprId,
285 },
286 /// An `if` expression.
287 If {
288 if_then_scope: region::Scope,
289 cond: ExprId,
290 then: ExprId,
291 else_opt: Option<ExprId>,
292 },
293 /// A function call. Method calls and overloaded operators are converted to plain function calls.
294 Call {
295 /// The type of the function. This is often a [`FnDef`] or a [`FnPtr`].
296 ///
297 /// [`FnDef`]: ty::TyKind::FnDef
298 /// [`FnPtr`]: ty::TyKind::FnPtr
299 ty: Ty<'tcx>,
300 /// The function itself.
301 fun: ExprId,
302 /// The arguments passed to the function.
303 ///
304 /// Note: in some cases (like calling a closure), the function call `f(...args)` gets
305 /// rewritten as a call to a function trait method (e.g. `FnOnce::call_once(f, (...args))`).
306 args: Box<[ExprId]>,
307 /// Whether this is from an overloaded operator rather than a
308 /// function call from HIR. `true` for overloaded function call.
309 from_hir_call: bool,
310 /// The span of the function, without the dot and receiver
311 /// (e.g. `foo(a, b)` in `x.foo(a, b)`).
312 fn_span: Span,
313 },
314 /// A *non-overloaded* dereference.
315 Deref {
316 arg: ExprId,
317 },
318 /// A *non-overloaded* binary operation.
319 Binary {
320 op: BinOp,
321 lhs: ExprId,
322 rhs: ExprId,
323 },
324 /// A logical operation. This is distinct from `BinaryOp` because
325 /// the operands need to be lazily evaluated.
326 LogicalOp {
327 op: LogicalOp,
328 lhs: ExprId,
329 rhs: ExprId,
330 },
331 /// A *non-overloaded* unary operation. Note that here the deref (`*`)
332 /// operator is represented by `ExprKind::Deref`.
333 Unary {
334 op: UnOp,
335 arg: ExprId,
336 },
337 /// A cast: `<source> as <type>`. The type we cast to is the type of
338 /// the parent expression.
339 Cast {
340 source: ExprId,
341 },
342 /// Forces its contents to be treated as a value expression, not a place
343 /// expression. This is inserted in some places where an operation would
344 /// otherwise be erased completely (e.g. some no-op casts), but we still
345 /// need to ensure that its operand is treated as a value and not a place.
346 Use {
347 source: ExprId,
348 },
349 /// A coercion from `!` to any type.
350 NeverToAny {
351 source: ExprId,
352 },
353 /// A pointer coercion. More information can be found in [`PointerCoercion`].
354 /// Pointer casts that cannot be done by coercions are represented by [`ExprKind::Cast`].
355 PointerCoercion {
356 cast: PointerCoercion,
357 source: ExprId,
358 /// Whether this coercion is written with an `as` cast in the source code.
359 is_from_as_cast: bool,
360 },
361 /// A `loop` expression.
362 Loop {
363 body: ExprId,
364 },
365 /// Special expression representing the `let` part of an `if let` or similar construct
366 /// (including `if let` guards in match arms, and let-chains formed by `&&`).
367 ///
368 /// This isn't considered a real expression in surface Rust syntax, so it can
369 /// only appear in specific situations, such as within the condition of an `if`.
370 ///
371 /// (Not to be confused with [`StmtKind::Let`], which is a normal `let` statement.)
372 Let {
373 expr: ExprId,
374 pat: Box<Pat<'tcx>>,
375 },
376 /// A `match` expression.
377 Match {
378 scrutinee: ExprId,
379 scrutinee_hir_id: HirId,
380 arms: Box<[ArmId]>,
381 match_source: MatchSource,
382 },
383 /// A block.
384 Block {
385 block: BlockId,
386 },
387 /// An assignment: `lhs = rhs`.
388 Assign {
389 lhs: ExprId,
390 rhs: ExprId,
391 },
392 /// A *non-overloaded* operation assignment, e.g. `lhs += rhs`.
393 AssignOp {
394 op: BinOp,
395 lhs: ExprId,
396 rhs: ExprId,
397 },
398 /// Access to a field of a struct, a tuple, an union, or an enum.
399 Field {
400 lhs: ExprId,
401 /// Variant containing the field.
402 variant_index: VariantIdx,
403 /// This can be a named (`.foo`) or unnamed (`.0`) field.
404 name: FieldIdx,
405 },
406 /// A *non-overloaded* indexing operation.
407 Index {
408 lhs: ExprId,
409 index: ExprId,
410 },
411 /// A local variable.
412 VarRef {
413 id: LocalVarId,
414 },
415 /// Used to represent upvars mentioned in a closure/coroutine
416 UpvarRef {
417 /// DefId of the closure/coroutine
418 closure_def_id: DefId,
419
420 /// HirId of the root variable
421 var_hir_id: LocalVarId,
422 },
423 /// A borrow, e.g. `&arg`.
424 Borrow {
425 borrow_kind: BorrowKind,
426 arg: ExprId,
427 },
428 /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
429 RawBorrow {
430 mutability: hir::Mutability,
431 arg: ExprId,
432 },
433 /// A `break` expression.
434 Break {
435 label: region::Scope,
436 value: Option<ExprId>,
437 },
438 /// A `continue` expression.
439 Continue {
440 label: region::Scope,
441 },
442 /// A `return` expression.
443 Return {
444 value: Option<ExprId>,
445 },
446 /// A `become` expression.
447 Become {
448 value: ExprId,
449 },
450 /// An inline `const` block, e.g. `const {}`.
451 ConstBlock {
452 did: DefId,
453 args: GenericArgsRef<'tcx>,
454 },
455 /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
456 Repeat {
457 value: ExprId,
458 count: ty::Const<'tcx>,
459 },
460 /// An array, e.g. `[a, b, c, d]`.
461 Array {
462 fields: Box<[ExprId]>,
463 },
464 /// A tuple, e.g. `(a, b, c, d)`.
465 Tuple {
466 fields: Box<[ExprId]>,
467 },
468 /// An ADT constructor, e.g. `Foo {x: 1, y: 2}`.
469 Adt(Box<AdtExpr<'tcx>>),
470 /// A type ascription on a place.
471 PlaceTypeAscription {
472 source: ExprId,
473 /// Type that the user gave to this expression
474 user_ty: UserTy<'tcx>,
475 user_ty_span: Span,
476 },
477 /// A type ascription on a value, e.g. `type_ascribe!(42, i32)` or `42 as i32`.
478 ValueTypeAscription {
479 source: ExprId,
480 /// Type that the user gave to this expression
481 user_ty: UserTy<'tcx>,
482 user_ty_span: Span,
483 },
484 /// An unsafe binder cast on a place, e.g. `unwrap_binder!(*ptr)`.
485 PlaceUnwrapUnsafeBinder {
486 source: ExprId,
487 },
488 /// An unsafe binder cast on a value, e.g. `unwrap_binder!(rvalue())`,
489 /// which makes a temporary.
490 ValueUnwrapUnsafeBinder {
491 source: ExprId,
492 },
493 /// Construct an unsafe binder, e.g. `wrap_binder(&ref)`.
494 WrapUnsafeBinder {
495 source: ExprId,
496 },
497 /// A closure definition.
498 Closure(Box<ClosureExpr<'tcx>>),
499 /// A literal.
500 Literal {
501 lit: &'tcx hir::Lit,
502 neg: bool,
503 },
504 /// For literals that don't correspond to anything in the HIR
505 NonHirLiteral {
506 lit: ty::ScalarInt,
507 user_ty: UserTy<'tcx>,
508 },
509 /// A literal of a ZST type.
510 ZstLiteral {
511 user_ty: UserTy<'tcx>,
512 },
513 /// Associated constants and named constants
514 NamedConst {
515 def_id: DefId,
516 args: GenericArgsRef<'tcx>,
517 user_ty: UserTy<'tcx>,
518 },
519 ConstParam {
520 param: ty::ParamConst,
521 def_id: DefId,
522 },
523 // FIXME improve docs for `StaticRef` by distinguishing it from `NamedConst`
524 /// A literal containing the address of a `static`.
525 ///
526 /// This is only distinguished from `Literal` so that we can register some
527 /// info for diagnostics.
528 StaticRef {
529 alloc_id: AllocId,
530 ty: Ty<'tcx>,
531 def_id: DefId,
532 },
533 /// Inline assembly, i.e. `asm!()`.
534 InlineAsm(Box<InlineAsmExpr<'tcx>>),
535 /// Field offset (`offset_of!`)
536 OffsetOf {
537 container: Ty<'tcx>,
538 fields: &'tcx List<(VariantIdx, FieldIdx)>,
539 },
540 /// An expression taking a reference to a thread local.
541 ThreadLocalRef(DefId),
542 /// A `yield` expression.
543 Yield {
544 value: ExprId,
545 },
546}
547
548/// Represents the association of a field identifier and an expression.
549///
550/// This is used in struct constructors.
551#[derive(Debug, HashStable)]
552pub struct FieldExpr {
553 pub name: FieldIdx,
554 pub expr: ExprId,
555}
556
557#[derive(Debug, HashStable)]
558pub struct FruInfo<'tcx> {
559 pub base: ExprId,
560 pub field_types: Box<[Ty<'tcx>]>,
561}
562
563/// A `match` arm.
564#[derive(Debug, HashStable)]
565pub struct Arm<'tcx> {
566 pub pattern: Box<Pat<'tcx>>,
567 pub guard: Option<ExprId>,
568 pub body: ExprId,
569 pub lint_level: LintLevel,
570 pub scope: region::Scope,
571 pub span: Span,
572}
573
574#[derive(Copy, Clone, Debug, HashStable)]
575pub enum LogicalOp {
576 /// The `&&` operator.
577 And,
578 /// The `||` operator.
579 Or,
580}
581
582#[derive(Debug, HashStable)]
583pub enum InlineAsmOperand<'tcx> {
584 In {
585 reg: InlineAsmRegOrRegClass,
586 expr: ExprId,
587 },
588 Out {
589 reg: InlineAsmRegOrRegClass,
590 late: bool,
591 expr: Option<ExprId>,
592 },
593 InOut {
594 reg: InlineAsmRegOrRegClass,
595 late: bool,
596 expr: ExprId,
597 },
598 SplitInOut {
599 reg: InlineAsmRegOrRegClass,
600 late: bool,
601 in_expr: ExprId,
602 out_expr: Option<ExprId>,
603 },
604 Const {
605 value: mir::Const<'tcx>,
606 span: Span,
607 },
608 SymFn {
609 value: mir::Const<'tcx>,
610 span: Span,
611 },
612 SymStatic {
613 def_id: DefId,
614 },
615 Label {
616 block: BlockId,
617 },
618}
619
620#[derive(Debug, HashStable, TypeVisitable)]
621pub struct FieldPat<'tcx> {
622 pub field: FieldIdx,
623 pub pattern: Pat<'tcx>,
624}
625
626#[derive(Debug, HashStable, TypeVisitable)]
627pub struct Pat<'tcx> {
628 pub ty: Ty<'tcx>,
629 pub span: Span,
630 pub kind: PatKind<'tcx>,
631}
632
633impl<'tcx> Pat<'tcx> {
634 pub fn simple_ident(&self) -> Option<Symbol> {
635 match self.kind {
636 PatKind::Binding {
637 name, mode: BindingMode(ByRef::No, _), subpattern: None, ..
638 } => Some(name),
639 _ => None,
640 }
641 }
642
643 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
644 /// `match foo() { Some(a) => (), None => () }`
645 pub fn each_binding(&self, mut f: impl FnMut(Symbol, ByRef, Ty<'tcx>, Span)) {
646 self.walk_always(|p| {
647 if let PatKind::Binding { name, mode, ty, .. } = p.kind {
648 f(name, mode.0, ty, p.span);
649 }
650 });
651 }
652
653 /// Walk the pattern in left-to-right order.
654 ///
655 /// If `it(pat)` returns `false`, the children are not visited.
656 pub fn walk(&self, mut it: impl FnMut(&Pat<'tcx>) -> bool) {
657 self.walk_(&mut it)
658 }
659
660 fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
661 if !it(self) {
662 return;
663 }
664
665 use PatKind::*;
666 match &self.kind {
667 Wild
668 | Never
669 | Range(..)
670 | Binding { subpattern: None, .. }
671 | Constant { .. }
672 | Error(_) => {}
673 AscribeUserType { subpattern, .. }
674 | Binding { subpattern: Some(subpattern), .. }
675 | Deref { subpattern }
676 | DerefPattern { subpattern, .. }
677 | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
678 Leaf { subpatterns } | Variant { subpatterns, .. } => {
679 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
680 }
681 Or { pats } => pats.iter().for_each(|p| p.walk_(it)),
682 Array { box ref prefix, ref slice, box ref suffix }
683 | Slice { box ref prefix, ref slice, box ref suffix } => {
684 prefix.iter().chain(slice.as_deref()).chain(suffix.iter()).for_each(|p| p.walk_(it))
685 }
686 }
687 }
688
689 /// Whether the pattern has a `PatKind::Error` nested within.
690 pub fn pat_error_reported(&self) -> Result<(), ErrorGuaranteed> {
691 let mut error = None;
692 self.walk(|pat| {
693 if let PatKind::Error(e) = pat.kind
694 && error.is_none()
695 {
696 error = Some(e);
697 }
698 error.is_none()
699 });
700 match error {
701 None => Ok(()),
702 Some(e) => Err(e),
703 }
704 }
705
706 /// Walk the pattern in left-to-right order.
707 ///
708 /// If you always want to recurse, prefer this method over `walk`.
709 pub fn walk_always(&self, mut it: impl FnMut(&Pat<'tcx>)) {
710 self.walk(|p| {
711 it(p);
712 true
713 })
714 }
715
716 /// Whether this a never pattern.
717 pub fn is_never_pattern(&self) -> bool {
718 let mut is_never_pattern = false;
719 self.walk(|pat| match &pat.kind {
720 PatKind::Never => {
721 is_never_pattern = true;
722 false
723 }
724 PatKind::Or { pats } => {
725 is_never_pattern = pats.iter().all(|p| p.is_never_pattern());
726 false
727 }
728 _ => true,
729 });
730 is_never_pattern
731 }
732}
733
734#[derive(Debug, HashStable, TypeVisitable)]
735pub struct Ascription<'tcx> {
736 pub annotation: CanonicalUserTypeAnnotation<'tcx>,
737 /// Variance to use when relating the `user_ty` to the **type of the value being
738 /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
739 /// have a type that is some subtype of the ascribed type.
740 ///
741 /// Note that this variance does not apply for any bindings within subpatterns. The type
742 /// assigned to those bindings must be exactly equal to the `user_ty` given here.
743 ///
744 /// The only place where this field is not `Covariant` is when matching constants, where
745 /// we currently use `Contravariant` -- this is because the constant type just needs to
746 /// be "comparable" to the type of the input value. So, for example:
747 ///
748 /// ```text
749 /// match x { "foo" => .. }
750 /// ```
751 ///
752 /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
753 /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
754 /// of the old type-check for now. See #57280 for details.
755 pub variance: ty::Variance,
756}
757
758#[derive(Debug, HashStable, TypeVisitable)]
759pub enum PatKind<'tcx> {
760 /// A wildcard pattern: `_`.
761 Wild,
762
763 AscribeUserType {
764 ascription: Ascription<'tcx>,
765 subpattern: Box<Pat<'tcx>>,
766 },
767
768 /// `x`, `ref x`, `x @ P`, etc.
769 Binding {
770 name: Symbol,
771 #[type_visitable(ignore)]
772 mode: BindingMode,
773 #[type_visitable(ignore)]
774 var: LocalVarId,
775 ty: Ty<'tcx>,
776 subpattern: Option<Box<Pat<'tcx>>>,
777 /// Is this the leftmost occurrence of the binding, i.e., is `var` the
778 /// `HirId` of this pattern?
779 is_primary: bool,
780 },
781
782 /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
783 /// multiple variants.
784 Variant {
785 adt_def: AdtDef<'tcx>,
786 args: GenericArgsRef<'tcx>,
787 variant_index: VariantIdx,
788 subpatterns: Vec<FieldPat<'tcx>>,
789 },
790
791 /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
792 /// a single variant.
793 Leaf {
794 subpatterns: Vec<FieldPat<'tcx>>,
795 },
796
797 /// `box P`, `&P`, `&mut P`, etc.
798 Deref {
799 subpattern: Box<Pat<'tcx>>,
800 },
801
802 /// Deref pattern, written `box P` for now.
803 DerefPattern {
804 subpattern: Box<Pat<'tcx>>,
805 mutability: hir::Mutability,
806 },
807
808 /// One of the following:
809 /// * `&str`/`&[u8]` (represented as a valtree), which will be handled as a string/slice pattern
810 /// and thus exhaustiveness checking will detect if you use the same string/slice twice in
811 /// different patterns.
812 /// * integer, bool, char or float (represented as a valtree), which will be handled by
813 /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
814 /// much simpler.
815 /// * `String`, if `string_deref_patterns` is enabled.
816 Constant {
817 value: mir::Const<'tcx>,
818 },
819
820 /// Pattern obtained by converting a constant (inline or named) to its pattern
821 /// representation using `const_to_pat`.
822 ExpandedConstant {
823 /// [DefId] of the constant, we need this so that we have a
824 /// reference that can be used by unsafety checking to visit nested
825 /// unevaluated constants and for diagnostics. If the `DefId` doesn't
826 /// correspond to a local crate, it points at the `const` item.
827 def_id: DefId,
828 /// If `false`, then `def_id` points at a `const` item, otherwise it
829 /// corresponds to a local inline const.
830 is_inline: bool,
831 /// If the inline constant is used in a range pattern, this subpattern
832 /// represents the range (if both ends are inline constants, there will
833 /// be multiple InlineConstant wrappers).
834 ///
835 /// Otherwise, the actual pattern that the constant lowered to. As with
836 /// other constants, inline constants are matched structurally where
837 /// possible.
838 subpattern: Box<Pat<'tcx>>,
839 },
840
841 Range(Arc<PatRange<'tcx>>),
842
843 /// Matches against a slice, checking the length and extracting elements.
844 /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
845 /// e.g., `&[ref xs @ ..]`.
846 Slice {
847 prefix: Box<[Pat<'tcx>]>,
848 slice: Option<Box<Pat<'tcx>>>,
849 suffix: Box<[Pat<'tcx>]>,
850 },
851
852 /// Fixed match against an array; irrefutable.
853 Array {
854 prefix: Box<[Pat<'tcx>]>,
855 slice: Option<Box<Pat<'tcx>>>,
856 suffix: Box<[Pat<'tcx>]>,
857 },
858
859 /// An or-pattern, e.g. `p | q`.
860 /// Invariant: `pats.len() >= 2`.
861 Or {
862 pats: Box<[Pat<'tcx>]>,
863 },
864
865 /// A never pattern `!`.
866 Never,
867
868 /// An error has been encountered during lowering. We probably shouldn't report more lints
869 /// related to this pattern.
870 Error(ErrorGuaranteed),
871}
872
873/// A range pattern.
874/// The boundaries must be of the same type and that type must be numeric.
875#[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)]
876pub struct PatRange<'tcx> {
877 /// Must not be `PosInfinity`.
878 pub lo: PatRangeBoundary<'tcx>,
879 /// Must not be `NegInfinity`.
880 pub hi: PatRangeBoundary<'tcx>,
881 #[type_visitable(ignore)]
882 pub end: RangeEnd,
883 pub ty: Ty<'tcx>,
884}
885
886impl<'tcx> PatRange<'tcx> {
887 /// Whether this range covers the full extent of possible values (best-effort, we ignore floats).
888 #[inline]
889 pub fn is_full_range(&self, tcx: TyCtxt<'tcx>) -> Option<bool> {
890 let (min, max, size, bias) = match *self.ty.kind() {
891 ty::Char => (0, std::char::MAX as u128, Size::from_bits(32), 0),
892 ty::Int(ity) => {
893 let size = Integer::from_int_ty(&tcx, ity).size();
894 let max = size.truncate(u128::MAX);
895 let bias = 1u128 << (size.bits() - 1);
896 (0, max, size, bias)
897 }
898 ty::Uint(uty) => {
899 let size = Integer::from_uint_ty(&tcx, uty).size();
900 let max = size.unsigned_int_max();
901 (0, max, size, 0)
902 }
903 _ => return None,
904 };
905
906 // We want to compare ranges numerically, but the order of the bitwise representation of
907 // signed integers does not match their numeric order. Thus, to correct the ordering, we
908 // need to shift the range of signed integers to correct the comparison. This is achieved by
909 // XORing with a bias (see pattern/deconstruct_pat.rs for another pertinent example of this
910 // pattern).
911 //
912 // Also, for performance, it's important to only do the second `try_to_bits` if necessary.
913 let lo_is_min = match self.lo {
914 PatRangeBoundary::NegInfinity => true,
915 PatRangeBoundary::Finite(value) => {
916 let lo = value.try_to_bits(size).unwrap() ^ bias;
917 lo <= min
918 }
919 PatRangeBoundary::PosInfinity => false,
920 };
921 if lo_is_min {
922 let hi_is_max = match self.hi {
923 PatRangeBoundary::NegInfinity => false,
924 PatRangeBoundary::Finite(value) => {
925 let hi = value.try_to_bits(size).unwrap() ^ bias;
926 hi > max || hi == max && self.end == RangeEnd::Included
927 }
928 PatRangeBoundary::PosInfinity => true,
929 };
930 if hi_is_max {
931 return Some(true);
932 }
933 }
934 Some(false)
935 }
936
937 #[inline]
938 pub fn contains(
939 &self,
940 value: mir::Const<'tcx>,
941 tcx: TyCtxt<'tcx>,
942 typing_env: ty::TypingEnv<'tcx>,
943 ) -> Option<bool> {
944 use Ordering::*;
945 debug_assert_eq!(self.ty, value.ty());
946 let ty = self.ty;
947 let value = PatRangeBoundary::Finite(value);
948 // For performance, it's important to only do the second comparison if necessary.
949 Some(
950 match self.lo.compare_with(value, ty, tcx, typing_env)? {
951 Less | Equal => true,
952 Greater => false,
953 } && match value.compare_with(self.hi, ty, tcx, typing_env)? {
954 Less => true,
955 Equal => self.end == RangeEnd::Included,
956 Greater => false,
957 },
958 )
959 }
960
961 #[inline]
962 pub fn overlaps(
963 &self,
964 other: &Self,
965 tcx: TyCtxt<'tcx>,
966 typing_env: ty::TypingEnv<'tcx>,
967 ) -> Option<bool> {
968 use Ordering::*;
969 debug_assert_eq!(self.ty, other.ty);
970 // For performance, it's important to only do the second comparison if necessary.
971 Some(
972 match other.lo.compare_with(self.hi, self.ty, tcx, typing_env)? {
973 Less => true,
974 Equal => self.end == RangeEnd::Included,
975 Greater => false,
976 } && match self.lo.compare_with(other.hi, self.ty, tcx, typing_env)? {
977 Less => true,
978 Equal => other.end == RangeEnd::Included,
979 Greater => false,
980 },
981 )
982 }
983}
984
985impl<'tcx> fmt::Display for PatRange<'tcx> {
986 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
987 if let PatRangeBoundary::Finite(value) = &self.lo {
988 write!(f, "{value}")?;
989 }
990 if let PatRangeBoundary::Finite(value) = &self.hi {
991 write!(f, "{}", self.end)?;
992 write!(f, "{value}")?;
993 } else {
994 // `0..` is parsed as an inclusive range, we must display it correctly.
995 write!(f, "..")?;
996 }
997 Ok(())
998 }
999}
1000
1001/// A (possibly open) boundary of a range pattern.
1002/// If present, the const must be of a numeric type.
1003#[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)]
1004pub enum PatRangeBoundary<'tcx> {
1005 Finite(mir::Const<'tcx>),
1006 NegInfinity,
1007 PosInfinity,
1008}
1009
1010impl<'tcx> PatRangeBoundary<'tcx> {
1011 #[inline]
1012 pub fn is_finite(self) -> bool {
1013 matches!(self, Self::Finite(..))
1014 }
1015 #[inline]
1016 pub fn as_finite(self) -> Option<mir::Const<'tcx>> {
1017 match self {
1018 Self::Finite(value) => Some(value),
1019 Self::NegInfinity | Self::PosInfinity => None,
1020 }
1021 }
1022 pub fn eval_bits(
1023 self,
1024 ty: Ty<'tcx>,
1025 tcx: TyCtxt<'tcx>,
1026 typing_env: ty::TypingEnv<'tcx>,
1027 ) -> u128 {
1028 match self {
1029 Self::Finite(value) => value.eval_bits(tcx, typing_env),
1030 Self::NegInfinity => {
1031 // Unwrap is ok because the type is known to be numeric.
1032 ty.numeric_min_and_max_as_bits(tcx).unwrap().0
1033 }
1034 Self::PosInfinity => {
1035 // Unwrap is ok because the type is known to be numeric.
1036 ty.numeric_min_and_max_as_bits(tcx).unwrap().1
1037 }
1038 }
1039 }
1040
1041 #[instrument(skip(tcx, typing_env), level = "debug", ret)]
1042 pub fn compare_with(
1043 self,
1044 other: Self,
1045 ty: Ty<'tcx>,
1046 tcx: TyCtxt<'tcx>,
1047 typing_env: ty::TypingEnv<'tcx>,
1048 ) -> Option<Ordering> {
1049 use PatRangeBoundary::*;
1050 match (self, other) {
1051 // When comparing with infinities, we must remember that `0u8..` and `0u8..=255`
1052 // describe the same range. These two shortcuts are ok, but for the rest we must check
1053 // bit values.
1054 (PosInfinity, PosInfinity) => return Some(Ordering::Equal),
1055 (NegInfinity, NegInfinity) => return Some(Ordering::Equal),
1056
1057 // This code is hot when compiling matches with many ranges. So we
1058 // special-case extraction of evaluated scalars for speed, for types where
1059 // we can do scalar comparisons. E.g. `unicode-normalization` has
1060 // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
1061 // in this way.
1062 (Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => {
1063 if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) {
1064 let sz = ty.primitive_size(tcx);
1065 let cmp = match ty.kind() {
1066 ty::Uint(_) | ty::Char => a.to_uint(sz).cmp(&b.to_uint(sz)),
1067 ty::Int(_) => a.to_int(sz).cmp(&b.to_int(sz)),
1068 _ => unreachable!(),
1069 };
1070 return Some(cmp);
1071 }
1072 }
1073 _ => {}
1074 }
1075
1076 let a = self.eval_bits(ty, tcx, typing_env);
1077 let b = other.eval_bits(ty, tcx, typing_env);
1078
1079 match ty.kind() {
1080 ty::Float(ty::FloatTy::F16) => {
1081 use rustc_apfloat::Float;
1082 let a = rustc_apfloat::ieee::Half::from_bits(a);
1083 let b = rustc_apfloat::ieee::Half::from_bits(b);
1084 a.partial_cmp(&b)
1085 }
1086 ty::Float(ty::FloatTy::F32) => {
1087 use rustc_apfloat::Float;
1088 let a = rustc_apfloat::ieee::Single::from_bits(a);
1089 let b = rustc_apfloat::ieee::Single::from_bits(b);
1090 a.partial_cmp(&b)
1091 }
1092 ty::Float(ty::FloatTy::F64) => {
1093 use rustc_apfloat::Float;
1094 let a = rustc_apfloat::ieee::Double::from_bits(a);
1095 let b = rustc_apfloat::ieee::Double::from_bits(b);
1096 a.partial_cmp(&b)
1097 }
1098 ty::Float(ty::FloatTy::F128) => {
1099 use rustc_apfloat::Float;
1100 let a = rustc_apfloat::ieee::Quad::from_bits(a);
1101 let b = rustc_apfloat::ieee::Quad::from_bits(b);
1102 a.partial_cmp(&b)
1103 }
1104 ty::Int(ity) => {
1105 let size = rustc_abi::Integer::from_int_ty(&tcx, *ity).size();
1106 let a = size.sign_extend(a) as i128;
1107 let b = size.sign_extend(b) as i128;
1108 Some(a.cmp(&b))
1109 }
1110 ty::Uint(_) | ty::Char => Some(a.cmp(&b)),
1111 _ => bug!(),
1112 }
1113 }
1114}
1115
1116// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
1117#[cfg(target_pointer_width = "64")]
1118mod size_asserts {
1119 use rustc_data_structures::static_assert_size;
1120
1121 use super::*;
1122 // tidy-alphabetical-start
1123 static_assert_size!(Block, 48);
1124 static_assert_size!(Expr<'_>, 72);
1125 static_assert_size!(ExprKind<'_>, 40);
1126 static_assert_size!(Pat<'_>, 64);
1127 static_assert_size!(PatKind<'_>, 48);
1128 static_assert_size!(Stmt<'_>, 48);
1129 static_assert_size!(StmtKind<'_>, 48);
1130 // tidy-alphabetical-end
1131}