]>
Commit | Line | Data |
---|---|---|
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 |
11 | use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; |
12 | use rustc_hir as hir; | |
13 | use rustc_hir::def::CtorKind; | |
14 | use rustc_hir::def_id::DefId; | |
15 | use rustc_hir::RangeEnd; | |
16 | use rustc_index::newtype_index; | |
94222f64 | 17 | use rustc_index::vec::IndexVec; |
17df50a5 XL |
18 | use rustc_middle::infer::canonical::Canonical; |
19 | use rustc_middle::middle::region; | |
5099ac24 | 20 | use rustc_middle::mir::interpret::AllocId; |
17df50a5 XL |
21 | use rustc_middle::mir::{ |
22 | BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection, | |
23 | }; | |
24 | use rustc_middle::ty::adjustment::PointerCast; | |
25 | use rustc_middle::ty::subst::SubstsRef; | |
26 | use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType}; | |
27 | use rustc_middle::ty::{ | |
28 | CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, | |
29 | }; | |
30 | use rustc_span::{Span, Symbol, DUMMY_SP}; | |
31 | use rustc_target::abi::VariantIdx; | |
32 | use rustc_target::asm::InlineAsmRegOrRegClass; | |
33 | ||
34 | use std::fmt; | |
35 | use std::ops::Index; | |
36 | ||
c295e0f8 XL |
37 | pub mod abstract_const; |
38 | pub mod visit; | |
39 | ||
17df50a5 | 40 | newtype_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 | ||
48 | newtype_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 | ||
56 | newtype_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 | ||
64 | macro_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 | ||
97 | thir_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)] | |
104 | pub enum LintLevel { | |
105 | Inherited, | |
106 | Explicit(hir::HirId), | |
107 | } | |
108 | ||
109 | #[derive(Debug, HashStable)] | |
110 | pub 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)] |
129 | pub 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)] |
146 | pub 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)] | |
155 | pub struct Stmt<'tcx> { | |
156 | pub kind: StmtKind<'tcx>, | |
157 | pub opt_destruction_scope: Option<region::Scope>, | |
158 | } | |
159 | ||
160 | #[derive(Debug, HashStable)] | |
161 | pub 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 |
196 | rustc_data_structures::static_assert_size!(Expr<'_>, 104); |
197 | ||
198 | /// A THIR expression. | |
17df50a5 XL |
199 | #[derive(Debug, HashStable)] |
200 | pub 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)] | |
216 | pub 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)] |
446 | pub struct FieldExpr { | |
447 | pub name: Field, | |
448 | pub expr: ExprId, | |
449 | } | |
450 | ||
451 | #[derive(Debug, HashStable)] | |
452 | pub 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)] |
459 | pub 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)] |
470 | pub enum Guard<'tcx> { | |
471 | If(ExprId), | |
472 | IfLet(Pat<'tcx>, ExprId), | |
473 | } | |
474 | ||
475 | #[derive(Copy, Clone, Debug, HashStable)] | |
476 | pub enum LogicalOp { | |
136023e0 | 477 | /// The `&&` operator. |
17df50a5 | 478 | And, |
136023e0 | 479 | /// The `||` operator. |
17df50a5 XL |
480 | Or, |
481 | } | |
482 | ||
483 | #[derive(Debug, HashStable)] | |
484 | pub 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)] | |
518 | pub enum BindingMode { | |
519 | ByValue, | |
520 | ByRef(BorrowKind), | |
521 | } | |
522 | ||
523 | #[derive(Clone, Debug, PartialEq, HashStable)] | |
524 | pub struct FieldPat<'tcx> { | |
525 | pub field: Field, | |
526 | pub pattern: Pat<'tcx>, | |
527 | } | |
528 | ||
529 | #[derive(Clone, Debug, PartialEq, HashStable)] | |
530 | pub struct Pat<'tcx> { | |
531 | pub ty: Ty<'tcx>, | |
532 | pub span: Span, | |
533 | pub kind: Box<PatKind<'tcx>>, | |
534 | } | |
535 | ||
536 | impl<'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)] | |
543 | pub struct PatTyProj<'tcx> { | |
544 | pub user_ty: CanonicalUserType<'tcx>, | |
545 | } | |
546 | ||
547 | impl<'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)] | |
570 | pub 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)] | |
595 | pub 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)] | |
674 | pub 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 | ||
680 | impl<'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 | } |