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