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