]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/thir.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / thir.rs
CommitLineData
136023e0
XL
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
17df50a5
XL
11use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
12use rustc_hir as hir;
13use rustc_hir::def::CtorKind;
14use rustc_hir::def_id::DefId;
15use rustc_hir::RangeEnd;
16use rustc_index::newtype_index;
94222f64 17use rustc_index::vec::IndexVec;
17df50a5 18use rustc_middle::middle::region;
5099ac24 19use rustc_middle::mir::interpret::AllocId;
923072b8 20use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
17df50a5
XL
21use rustc_middle::ty::adjustment::PointerCast;
22use rustc_middle::ty::subst::SubstsRef;
f2b60f7d
FG
23use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts};
24use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
25use rustc_span::def_id::LocalDefId;
26use rustc_span::{sym, Span, Symbol, DUMMY_SP};
17df50a5
XL
27use rustc_target::abi::VariantIdx;
28use rustc_target::asm::InlineAsmRegOrRegClass;
17df50a5
XL
29use std::fmt;
30use std::ops::Index;
31
c295e0f8
XL
32pub mod visit;
33
17df50a5 34macro_rules! thir_with_elements {
f2b60f7d
FG
35 ($($name:ident: $id:ty => $value:ty => $format:literal,)*) => {
36 $(
37 newtype_index! {
38 #[derive(HashStable)]
39 pub struct $id {
40 DEBUG_FORMAT = $format
41 }
42 }
43 )*
44
136023e0
XL
45 /// A container for a THIR body.
46 ///
47 /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
04454e1e 48 #[derive(Debug, HashStable, Clone)]
17df50a5
XL
49 pub struct Thir<'tcx> {
50 $(
51 pub $name: IndexVec<$id, $value>,
52 )*
53 }
54
55 impl<'tcx> Thir<'tcx> {
56 pub fn new() -> Thir<'tcx> {
57 Thir {
58 $(
59 $name: IndexVec::new(),
60 )*
61 }
62 }
63 }
64
65 $(
66 impl<'tcx> Index<$id> for Thir<'tcx> {
67 type Output = $value;
68 fn index(&self, index: $id) -> &Self::Output {
69 &self.$name[index]
70 }
71 }
72 )*
73 }
74}
75
f2b60f7d
FG
76pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0);
77
17df50a5 78thir_with_elements! {
f2b60f7d
FG
79 arms: ArmId => Arm<'tcx> => "a{}",
80 blocks: BlockId => Block => "b{}",
81 exprs: ExprId => Expr<'tcx> => "e{}",
82 stmts: StmtId => Stmt<'tcx> => "s{}",
83 params: ParamId => Param<'tcx> => "p{}",
84}
85
86/// Description of a type-checked function parameter.
87#[derive(Clone, Debug, HashStable)]
88pub struct Param<'tcx> {
89 /// The pattern that appears in the parameter list, or None for implicit parameters.
90 pub pat: Option<Box<Pat<'tcx>>>,
91 /// The possibly inferred type.
92 pub ty: Ty<'tcx>,
93 /// Span of the explicitly provided type, or None if inferred for closures.
94 pub ty_span: Option<Span>,
95 /// Whether this param is `self`, and how it is bound.
96 pub self_kind: Option<hir::ImplicitSelfKind>,
97 /// HirId for lints.
98 pub hir_id: Option<hir::HirId>,
17df50a5
XL
99}
100
101#[derive(Copy, Clone, Debug, HashStable)]
102pub enum LintLevel {
103 Inherited,
104 Explicit(hir::HirId),
105}
106
04454e1e 107#[derive(Clone, Debug, HashStable)]
17df50a5 108pub struct Block {
136023e0
XL
109 /// Whether the block itself has a label. Used by `label: {}`
110 /// and `try` blocks.
111 ///
112 /// This does *not* include labels on loops, e.g. `'label: loop {}`.
17df50a5
XL
113 pub targeted_by_break: bool,
114 pub region_scope: region::Scope,
115 pub opt_destruction_scope: Option<region::Scope>,
136023e0
XL
116 /// The span of the block, including the opening braces,
117 /// the label, and the `unsafe` keyword, if present.
17df50a5 118 pub span: Span,
136023e0 119 /// The statements in the blocK.
17df50a5 120 pub stmts: Box<[StmtId]>,
136023e0 121 /// The trailing expression of the block, if any.
17df50a5
XL
122 pub expr: Option<ExprId>,
123 pub safety_mode: BlockSafety,
124}
125
f2b60f7d
FG
126type UserTy<'tcx> = Option<Box<CanonicalUserType<'tcx>>>;
127
04454e1e 128#[derive(Clone, Debug, HashStable)]
f2b60f7d 129pub struct AdtExpr<'tcx> {
136023e0 130 /// The ADT we're constructing.
5e7ed085 131 pub adt_def: AdtDef<'tcx>,
136023e0
XL
132 /// The variant of the ADT.
133 pub variant_index: VariantIdx,
134 pub substs: SubstsRef<'tcx>,
135
136 /// Optional user-given substs: for something like `let x =
137 /// Bar::<T> { ... }`.
f2b60f7d 138 pub user_ty: UserTy<'tcx>,
136023e0
XL
139
140 pub fields: Box<[FieldExpr]>,
141 /// The base, e.g. `Foo {x: 1, .. base}`.
142 pub base: Option<FruInfo<'tcx>>,
143}
144
f2b60f7d
FG
145#[derive(Clone, Debug, HashStable)]
146pub struct ClosureExpr<'tcx> {
147 pub closure_id: LocalDefId,
148 pub substs: UpvarSubsts<'tcx>,
149 pub upvars: Box<[ExprId]>,
150 pub movability: Option<hir::Movability>,
151 pub fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
152}
153
154#[derive(Clone, Debug, HashStable)]
155pub struct InlineAsmExpr<'tcx> {
156 pub template: &'tcx [InlineAsmTemplatePiece],
157 pub operands: Box<[InlineAsmOperand<'tcx>]>,
158 pub options: InlineAsmOptions,
159 pub line_spans: &'tcx [Span],
160}
161
17df50a5
XL
162#[derive(Copy, Clone, Debug, HashStable)]
163pub enum BlockSafety {
164 Safe,
136023e0
XL
165 /// A compiler-generated unsafe block
166 BuiltinUnsafe,
167 /// An `unsafe` block. The `HirId` is the ID of the block.
17df50a5 168 ExplicitUnsafe(hir::HirId),
17df50a5
XL
169}
170
04454e1e 171#[derive(Clone, Debug, HashStable)]
17df50a5
XL
172pub struct Stmt<'tcx> {
173 pub kind: StmtKind<'tcx>,
174 pub opt_destruction_scope: Option<region::Scope>,
175}
176
04454e1e 177#[derive(Clone, Debug, HashStable)]
17df50a5 178pub enum StmtKind<'tcx> {
136023e0 179 /// An expression with a trailing semicolon.
17df50a5 180 Expr {
136023e0 181 /// The scope for this statement; may be used as lifetime of temporaries.
17df50a5
XL
182 scope: region::Scope,
183
136023e0 184 /// The expression being evaluated in this statement.
17df50a5
XL
185 expr: ExprId,
186 },
187
136023e0 188 /// A `let` binding.
17df50a5 189 Let {
136023e0
XL
190 /// The scope for variables bound in this `let`; it covers this and
191 /// all the remaining statements in the block.
17df50a5
XL
192 remainder_scope: region::Scope,
193
136023e0
XL
194 /// The scope for the initialization itself; might be used as
195 /// lifetime of temporaries.
17df50a5
XL
196 init_scope: region::Scope,
197
198 /// `let <PAT> = ...`
199 ///
136023e0 200 /// If a type annotation is included, it is added as an ascription pattern.
f2b60f7d 201 pattern: Box<Pat<'tcx>>,
17df50a5 202
136023e0 203 /// `let pat: ty = <INIT>`
17df50a5
XL
204 initializer: Option<ExprId>,
205
2b03887a 206 /// `let pat: ty = <INIT> else { <ELSE> }`
f2b60f7d 207 else_block: Option<BlockId>,
064997fb 208
136023e0 209 /// The lint level for this `let` statement.
17df50a5
XL
210 lint_level: LintLevel,
211 },
212}
213
064997fb
FG
214#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
215#[derive(TypeFoldable, TypeVisitable)]
923072b8
FG
216pub struct LocalVarId(pub hir::HirId);
217
136023e0 218/// A THIR expression.
04454e1e 219#[derive(Clone, Debug, HashStable)]
17df50a5 220pub struct Expr<'tcx> {
136023e0 221 /// The type of this expression
17df50a5
XL
222 pub ty: Ty<'tcx>,
223
136023e0
XL
224 /// The lifetime of this expression if it should be spilled into a
225 /// temporary; should be `None` only if in a constant context
17df50a5
XL
226 pub temp_lifetime: Option<region::Scope>,
227
228 /// span of the expression in the source
229 pub span: Span,
230
231 /// kind of expression
232 pub kind: ExprKind<'tcx>,
233}
234
04454e1e 235#[derive(Clone, Debug, HashStable)]
17df50a5 236pub enum ExprKind<'tcx> {
5099ac24 237 /// `Scope`s are used to explicitly mark destruction scopes,
136023e0 238 /// and to track the `HirId` of the expressions within the scope.
17df50a5
XL
239 Scope {
240 region_scope: region::Scope,
241 lint_level: LintLevel,
242 value: ExprId,
243 },
136023e0 244 /// A `box <value>` expression.
17df50a5
XL
245 Box {
246 value: ExprId,
247 },
136023e0 248 /// An `if` expression.
17df50a5 249 If {
94222f64 250 if_then_scope: region::Scope,
17df50a5
XL
251 cond: ExprId,
252 then: ExprId,
253 else_opt: Option<ExprId>,
254 },
136023e0 255 /// A function call. Method calls and overloaded operators are converted to plain function calls.
17df50a5 256 Call {
136023e0
XL
257 /// The type of the function. This is often a [`FnDef`] or a [`FnPtr`].
258 ///
259 /// [`FnDef`]: ty::TyKind::FnDef
260 /// [`FnPtr`]: ty::TyKind::FnPtr
17df50a5 261 ty: Ty<'tcx>,
136023e0 262 /// The function itself.
17df50a5 263 fun: ExprId,
136023e0
XL
264 /// The arguments passed to the function.
265 ///
266 /// Note: in some cases (like calling a closure), the function call `f(...args)` gets
267 /// rewritten as a call to a function trait method (e.g. `FnOnce::call_once(f, (...args))`).
17df50a5 268 args: Box<[ExprId]>,
136023e0
XL
269 /// Whether this is from an overloaded operator rather than a
270 /// function call from HIR. `true` for overloaded function call.
17df50a5 271 from_hir_call: bool,
136023e0
XL
272 /// The span of the function, without the dot and receiver
273 /// (e.g. `foo(a, b)` in `x.foo(a, b)`).
17df50a5
XL
274 fn_span: Span,
275 },
136023e0 276 /// A *non-overloaded* dereference.
17df50a5
XL
277 Deref {
278 arg: ExprId,
136023e0
XL
279 },
280 /// A *non-overloaded* binary operation.
17df50a5
XL
281 Binary {
282 op: BinOp,
283 lhs: ExprId,
284 rhs: ExprId,
136023e0
XL
285 },
286 /// A logical operation. This is distinct from `BinaryOp` because
287 /// the operands need to be lazily evaluated.
17df50a5
XL
288 LogicalOp {
289 op: LogicalOp,
290 lhs: ExprId,
291 rhs: ExprId,
136023e0
XL
292 },
293 /// A *non-overloaded* unary operation. Note that here the deref (`*`)
294 /// operator is represented by `ExprKind::Deref`.
17df50a5
XL
295 Unary {
296 op: UnOp,
297 arg: ExprId,
136023e0
XL
298 },
299 /// A cast: `<source> as <type>`. The type we cast to is the type of
300 /// the parent expression.
17df50a5
XL
301 Cast {
302 source: ExprId,
303 },
304 Use {
305 source: ExprId,
306 }, // Use a lexpr to get a vexpr.
136023e0 307 /// A coercion from `!` to any type.
17df50a5
XL
308 NeverToAny {
309 source: ExprId,
310 },
136023e0 311 /// A pointer cast. More information can be found in [`PointerCast`].
17df50a5
XL
312 Pointer {
313 cast: PointerCast,
314 source: ExprId,
315 },
136023e0 316 /// A `loop` expression.
17df50a5
XL
317 Loop {
318 body: ExprId,
319 },
94222f64
XL
320 Let {
321 expr: ExprId,
f2b60f7d 322 pat: Box<Pat<'tcx>>,
94222f64 323 },
136023e0 324 /// A `match` expression.
17df50a5
XL
325 Match {
326 scrutinee: ExprId,
327 arms: Box<[ArmId]>,
328 },
136023e0 329 /// A block.
17df50a5 330 Block {
f2b60f7d 331 block: BlockId,
17df50a5 332 },
136023e0 333 /// An assignment: `lhs = rhs`.
17df50a5
XL
334 Assign {
335 lhs: ExprId,
336 rhs: ExprId,
337 },
136023e0 338 /// A *non-overloaded* operation assignment, e.g. `lhs += rhs`.
17df50a5
XL
339 AssignOp {
340 op: BinOp,
341 lhs: ExprId,
342 rhs: ExprId,
343 },
923072b8 344 /// Access to a field of a struct, a tuple, an union, or an enum.
17df50a5
XL
345 Field {
346 lhs: ExprId,
923072b8
FG
347 /// Variant containing the field.
348 variant_index: VariantIdx,
136023e0 349 /// This can be a named (`.foo`) or unnamed (`.0`) field.
17df50a5
XL
350 name: Field,
351 },
136023e0 352 /// A *non-overloaded* indexing operation.
17df50a5
XL
353 Index {
354 lhs: ExprId,
355 index: ExprId,
356 },
136023e0 357 /// A local variable.
17df50a5 358 VarRef {
923072b8 359 id: LocalVarId,
17df50a5
XL
360 },
361 /// Used to represent upvars mentioned in a closure/generator
362 UpvarRef {
363 /// DefId of the closure/generator
364 closure_def_id: DefId,
365
366 /// HirId of the root variable
923072b8 367 var_hir_id: LocalVarId,
17df50a5 368 },
136023e0 369 /// A borrow, e.g. `&arg`.
17df50a5
XL
370 Borrow {
371 borrow_kind: BorrowKind,
372 arg: ExprId,
373 },
374 /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
375 AddressOf {
376 mutability: hir::Mutability,
377 arg: ExprId,
378 },
136023e0 379 /// A `break` expression.
17df50a5
XL
380 Break {
381 label: region::Scope,
382 value: Option<ExprId>,
383 },
136023e0 384 /// A `continue` expression.
17df50a5
XL
385 Continue {
386 label: region::Scope,
387 },
136023e0 388 /// A `return` expression.
17df50a5
XL
389 Return {
390 value: Option<ExprId>,
391 },
136023e0 392 /// An inline `const` block, e.g. `const {}`.
17df50a5 393 ConstBlock {
5e7ed085
FG
394 did: DefId,
395 substs: SubstsRef<'tcx>,
17df50a5 396 },
136023e0 397 /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
17df50a5
XL
398 Repeat {
399 value: ExprId,
04454e1e 400 count: ty::Const<'tcx>,
17df50a5 401 },
136023e0 402 /// An array, e.g. `[a, b, c, d]`.
17df50a5
XL
403 Array {
404 fields: Box<[ExprId]>,
405 },
136023e0 406 /// A tuple, e.g. `(a, b, c, d)`.
17df50a5
XL
407 Tuple {
408 fields: Box<[ExprId]>,
409 },
136023e0 410 /// An ADT constructor, e.g. `Foo {x: 1, y: 2}`.
f2b60f7d 411 Adt(Box<AdtExpr<'tcx>>),
136023e0 412 /// A type ascription on a place.
17df50a5
XL
413 PlaceTypeAscription {
414 source: ExprId,
415 /// Type that the user gave to this expression
f2b60f7d 416 user_ty: UserTy<'tcx>,
17df50a5 417 },
136023e0 418 /// A type ascription on a value, e.g. `42: i32`.
17df50a5
XL
419 ValueTypeAscription {
420 source: ExprId,
421 /// Type that the user gave to this expression
f2b60f7d 422 user_ty: UserTy<'tcx>,
17df50a5 423 },
136023e0 424 /// A closure definition.
f2b60f7d 425 Closure(Box<ClosureExpr<'tcx>>),
136023e0 426 /// A literal.
17df50a5 427 Literal {
5e7ed085
FG
428 lit: &'tcx hir::Lit,
429 neg: bool,
430 },
431 /// For literals that don't correspond to anything in the HIR
432 NonHirLiteral {
433 lit: ty::ScalarInt,
f2b60f7d 434 user_ty: UserTy<'tcx>,
5e7ed085 435 },
064997fb
FG
436 /// A literal of a ZST type.
437 ZstLiteral {
f2b60f7d 438 user_ty: UserTy<'tcx>,
064997fb 439 },
5e7ed085
FG
440 /// Associated constants and named constants
441 NamedConst {
442 def_id: DefId,
443 substs: SubstsRef<'tcx>,
f2b60f7d 444 user_ty: UserTy<'tcx>,
17df50a5 445 },
5e7ed085
FG
446 ConstParam {
447 param: ty::ParamConst,
448 def_id: DefId,
449 },
450 // FIXME improve docs for `StaticRef` by distinguishing it from `NamedConst`
17df50a5
XL
451 /// A literal containing the address of a `static`.
452 ///
453 /// This is only distinguished from `Literal` so that we can register some
454 /// info for diagnostics.
455 StaticRef {
5099ac24
FG
456 alloc_id: AllocId,
457 ty: Ty<'tcx>,
17df50a5
XL
458 def_id: DefId,
459 },
136023e0 460 /// Inline assembly, i.e. `asm!()`.
f2b60f7d 461 InlineAsm(Box<InlineAsmExpr<'tcx>>),
17df50a5
XL
462 /// An expression taking a reference to a thread local.
463 ThreadLocalRef(DefId),
136023e0 464 /// A `yield` expression.
17df50a5
XL
465 Yield {
466 value: ExprId,
467 },
468}
469
136023e0
XL
470/// Represents the association of a field identifier and an expression.
471///
472/// This is used in struct constructors.
04454e1e 473#[derive(Clone, Debug, HashStable)]
17df50a5
XL
474pub struct FieldExpr {
475 pub name: Field,
476 pub expr: ExprId,
477}
478
04454e1e 479#[derive(Clone, Debug, HashStable)]
17df50a5
XL
480pub struct FruInfo<'tcx> {
481 pub base: ExprId,
482 pub field_types: Box<[Ty<'tcx>]>,
483}
484
136023e0 485/// A `match` arm.
04454e1e 486#[derive(Clone, Debug, HashStable)]
17df50a5 487pub struct Arm<'tcx> {
f2b60f7d 488 pub pattern: Box<Pat<'tcx>>,
17df50a5
XL
489 pub guard: Option<Guard<'tcx>>,
490 pub body: ExprId,
491 pub lint_level: LintLevel,
492 pub scope: region::Scope,
493 pub span: Span,
494}
495
136023e0 496/// A `match` guard.
04454e1e 497#[derive(Clone, Debug, HashStable)]
17df50a5
XL
498pub enum Guard<'tcx> {
499 If(ExprId),
f2b60f7d 500 IfLet(Box<Pat<'tcx>>, ExprId),
17df50a5
XL
501}
502
503#[derive(Copy, Clone, Debug, HashStable)]
504pub enum LogicalOp {
136023e0 505 /// The `&&` operator.
17df50a5 506 And,
136023e0 507 /// The `||` operator.
17df50a5
XL
508 Or,
509}
510
04454e1e 511#[derive(Clone, Debug, HashStable)]
17df50a5
XL
512pub enum InlineAsmOperand<'tcx> {
513 In {
514 reg: InlineAsmRegOrRegClass,
515 expr: ExprId,
516 },
517 Out {
518 reg: InlineAsmRegOrRegClass,
519 late: bool,
520 expr: Option<ExprId>,
521 },
522 InOut {
523 reg: InlineAsmRegOrRegClass,
524 late: bool,
525 expr: ExprId,
526 },
527 SplitInOut {
528 reg: InlineAsmRegOrRegClass,
529 late: bool,
530 in_expr: ExprId,
531 out_expr: Option<ExprId>,
532 },
533 Const {
04454e1e 534 value: mir::ConstantKind<'tcx>,
17df50a5
XL
535 span: Span,
536 },
537 SymFn {
04454e1e
FG
538 value: mir::ConstantKind<'tcx>,
539 span: Span,
17df50a5
XL
540 },
541 SymStatic {
542 def_id: DefId,
543 },
544}
545
546#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
547pub enum BindingMode {
548 ByValue,
549 ByRef(BorrowKind),
550}
551
923072b8 552#[derive(Clone, Debug, HashStable)]
17df50a5
XL
553pub struct FieldPat<'tcx> {
554 pub field: Field,
f2b60f7d 555 pub pattern: Box<Pat<'tcx>>,
17df50a5
XL
556}
557
923072b8 558#[derive(Clone, Debug, HashStable)]
17df50a5
XL
559pub struct Pat<'tcx> {
560 pub ty: Ty<'tcx>,
561 pub span: Span,
f2b60f7d 562 pub kind: PatKind<'tcx>,
17df50a5
XL
563}
564
565impl<'tcx> Pat<'tcx> {
566 pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
f2b60f7d
FG
567 Pat { ty, span: DUMMY_SP, kind: PatKind::Wild }
568 }
569
570 pub fn simple_ident(&self) -> Option<Symbol> {
571 match self.kind {
572 PatKind::Binding { name, mode: BindingMode::ByValue, subpattern: None, .. } => {
573 Some(name)
574 }
575 _ => None,
576 }
17df50a5
XL
577 }
578}
579
923072b8 580#[derive(Clone, Debug, HashStable)]
17df50a5 581pub struct Ascription<'tcx> {
923072b8
FG
582 pub annotation: CanonicalUserTypeAnnotation<'tcx>,
583 /// Variance to use when relating the `user_ty` to the **type of the value being
17df50a5
XL
584 /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
585 /// have a type that is some subtype of the ascribed type.
586 ///
587 /// Note that this variance does not apply for any bindings within subpatterns. The type
588 /// assigned to those bindings must be exactly equal to the `user_ty` given here.
589 ///
590 /// The only place where this field is not `Covariant` is when matching constants, where
591 /// we currently use `Contravariant` -- this is because the constant type just needs to
592 /// be "comparable" to the type of the input value. So, for example:
593 ///
594 /// ```text
595 /// match x { "foo" => .. }
596 /// ```
597 ///
598 /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
599 /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
600 /// of the old type-check for now. See #57280 for details.
601 pub variance: ty::Variance,
17df50a5
XL
602}
603
923072b8 604#[derive(Clone, Debug, HashStable)]
17df50a5 605pub enum PatKind<'tcx> {
923072b8 606 /// A wildcard pattern: `_`.
17df50a5
XL
607 Wild,
608
609 AscribeUserType {
610 ascription: Ascription<'tcx>,
f2b60f7d 611 subpattern: Box<Pat<'tcx>>,
17df50a5
XL
612 },
613
614 /// `x`, `ref x`, `x @ P`, etc.
615 Binding {
616 mutability: Mutability,
617 name: Symbol,
618 mode: BindingMode,
923072b8 619 var: LocalVarId,
17df50a5 620 ty: Ty<'tcx>,
f2b60f7d 621 subpattern: Option<Box<Pat<'tcx>>>,
17df50a5
XL
622 /// Is this the leftmost occurrence of the binding, i.e., is `var` the
623 /// `HirId` of this pattern?
624 is_primary: bool,
625 },
626
627 /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
628 /// multiple variants.
629 Variant {
5e7ed085 630 adt_def: AdtDef<'tcx>,
17df50a5
XL
631 substs: SubstsRef<'tcx>,
632 variant_index: VariantIdx,
633 subpatterns: Vec<FieldPat<'tcx>>,
634 },
635
636 /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
637 /// a single variant.
638 Leaf {
639 subpatterns: Vec<FieldPat<'tcx>>,
640 },
641
642 /// `box P`, `&P`, `&mut P`, etc.
643 Deref {
f2b60f7d 644 subpattern: Box<Pat<'tcx>>,
17df50a5
XL
645 },
646
647 /// One of the following:
648 /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
649 /// checking will detect if you use the same string twice in different patterns.
5e7ed085 650 /// * integer, bool, char or float, which will be handled by exhaustiveness to cover exactly
17df50a5
XL
651 /// its own value, similar to `&str`, but these values are much simpler.
652 /// * Opaque constants, that must not be matched structurally. So anything that does not derive
653 /// `PartialEq` and `Eq`.
654 Constant {
923072b8 655 value: mir::ConstantKind<'tcx>,
17df50a5
XL
656 },
657
f2b60f7d 658 Range(Box<PatRange<'tcx>>),
17df50a5
XL
659
660 /// Matches against a slice, checking the length and extracting elements.
661 /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
662 /// e.g., `&[ref xs @ ..]`.
663 Slice {
f2b60f7d
FG
664 prefix: Box<[Box<Pat<'tcx>>]>,
665 slice: Option<Box<Pat<'tcx>>>,
666 suffix: Box<[Box<Pat<'tcx>>]>,
17df50a5
XL
667 },
668
669 /// Fixed match against an array; irrefutable.
670 Array {
f2b60f7d
FG
671 prefix: Box<[Box<Pat<'tcx>>]>,
672 slice: Option<Box<Pat<'tcx>>>,
673 suffix: Box<[Box<Pat<'tcx>>]>,
17df50a5
XL
674 },
675
676 /// An or-pattern, e.g. `p | q`.
677 /// Invariant: `pats.len() >= 2`.
678 Or {
f2b60f7d 679 pats: Box<[Box<Pat<'tcx>>]>,
17df50a5
XL
680 },
681}
682
f2b60f7d 683#[derive(Clone, Debug, PartialEq, HashStable)]
17df50a5 684pub struct PatRange<'tcx> {
923072b8
FG
685 pub lo: mir::ConstantKind<'tcx>,
686 pub hi: mir::ConstantKind<'tcx>,
17df50a5
XL
687 pub end: RangeEnd,
688}
689
690impl<'tcx> fmt::Display for Pat<'tcx> {
691 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692 // Printing lists is a chore.
693 let mut first = true;
694 let mut start_or_continue = |s| {
695 if first {
696 first = false;
697 ""
698 } else {
699 s
700 }
701 };
702 let mut start_or_comma = || start_or_continue(", ");
703
f2b60f7d 704 match self.kind {
17df50a5
XL
705 PatKind::Wild => write!(f, "_"),
706 PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
707 PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
708 let is_mut = match mode {
709 BindingMode::ByValue => mutability == Mutability::Mut,
710 BindingMode::ByRef(bk) => {
711 write!(f, "ref ")?;
712 matches!(bk, BorrowKind::Mut { .. })
713 }
714 };
715 if is_mut {
716 write!(f, "mut ")?;
717 }
718 write!(f, "{}", name)?;
719 if let Some(ref subpattern) = *subpattern {
720 write!(f, " @ {}", subpattern)?;
721 }
722 Ok(())
723 }
724 PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
f2b60f7d
FG
725 let variant_and_name = match self.kind {
726 PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
727 let variant = adt_def.variant(variant_index);
728 let adt_did = adt_def.did();
729 let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
730 || tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
731 {
732 variant.name.to_string()
733 } else {
734 format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
735 };
736 Some((variant, name))
737 }),
738 _ => self.ty.ty_adt_def().and_then(|adt_def| {
739 if !adt_def.is_enum() {
740 ty::tls::with(|tcx| {
741 Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
742 })
743 } else {
744 None
745 }
94222f64 746 }),
17df50a5
XL
747 };
748
f2b60f7d
FG
749 if let Some((variant, name)) = &variant_and_name {
750 write!(f, "{}", name)?;
17df50a5
XL
751
752 // Only for Adt we can have `S {...}`,
753 // which we handle separately here.
754 if variant.ctor_kind == CtorKind::Fictive {
755 write!(f, " {{ ")?;
756
757 let mut printed = 0;
758 for p in subpatterns {
f2b60f7d 759 if let PatKind::Wild = p.pattern.kind {
17df50a5
XL
760 continue;
761 }
5099ac24 762 let name = variant.fields[p.field.index()].name;
17df50a5
XL
763 write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
764 printed += 1;
765 }
766
767 if printed < variant.fields.len() {
768 write!(f, "{}..", start_or_comma())?;
769 }
770
771 return write!(f, " }}");
772 }
773 }
774
f2b60f7d
FG
775 let num_fields =
776 variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
777 if num_fields != 0 || variant_and_name.is_none() {
17df50a5
XL
778 write!(f, "(")?;
779 for i in 0..num_fields {
780 write!(f, "{}", start_or_comma())?;
781
782 // Common case: the field is where we expect it.
783 if let Some(p) = subpatterns.get(i) {
784 if p.field.index() == i {
785 write!(f, "{}", p.pattern)?;
786 continue;
787 }
788 }
789
790 // Otherwise, we have to go looking for it.
791 if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
792 write!(f, "{}", p.pattern)?;
793 } else {
794 write!(f, "_")?;
795 }
796 }
797 write!(f, ")")?;
798 }
799
800 Ok(())
801 }
802 PatKind::Deref { ref subpattern } => {
803 match self.ty.kind() {
804 ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
805 ty::Ref(_, _, mutbl) => {
806 write!(f, "&{}", mutbl.prefix_str())?;
807 }
808 _ => bug!("{} is a bad Deref pattern type", self.ty),
809 }
810 write!(f, "{}", subpattern)
811 }
812 PatKind::Constant { value } => write!(f, "{}", value),
f2b60f7d 813 PatKind::Range(box PatRange { lo, hi, end }) => {
17df50a5
XL
814 write!(f, "{}", lo)?;
815 write!(f, "{}", end)?;
816 write!(f, "{}", hi)
817 }
818 PatKind::Slice { ref prefix, ref slice, ref suffix }
819 | PatKind::Array { ref prefix, ref slice, ref suffix } => {
820 write!(f, "[")?;
f2b60f7d 821 for p in prefix.iter() {
17df50a5
XL
822 write!(f, "{}{}", start_or_comma(), p)?;
823 }
824 if let Some(ref slice) = *slice {
825 write!(f, "{}", start_or_comma())?;
f2b60f7d 826 match slice.kind {
17df50a5
XL
827 PatKind::Wild => {}
828 _ => write!(f, "{}", slice)?,
829 }
830 write!(f, "..")?;
831 }
f2b60f7d 832 for p in suffix.iter() {
17df50a5
XL
833 write!(f, "{}{}", start_or_comma(), p)?;
834 }
835 write!(f, "]")
836 }
837 PatKind::Or { ref pats } => {
f2b60f7d 838 for pat in pats.iter() {
17df50a5
XL
839 write!(f, "{}{}", start_or_continue(" | "), pat)?;
840 }
841 Ok(())
842 }
843 }
844 }
845}
064997fb
FG
846
847// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
848#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
849mod size_asserts {
850 use super::*;
2b03887a 851 // tidy-alphabetical-start
f2b60f7d
FG
852 static_assert_size!(Block, 56);
853 static_assert_size!(Expr<'_>, 64);
854 static_assert_size!(ExprKind<'_>, 40);
f2b60f7d 855 static_assert_size!(Pat<'_>, 72);
f2b60f7d 856 static_assert_size!(PatKind<'_>, 56);
f2b60f7d 857 static_assert_size!(Stmt<'_>, 48);
f2b60f7d 858 static_assert_size!(StmtKind<'_>, 40);
2b03887a 859 // tidy-alphabetical-end
064997fb 860}