]> git.proxmox.com Git - rustc.git/blob - src/doc/rustc-dev-guide/src/borrow_check/type_check.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / borrow_check / type_check.md
1 # The MIR type-check
2
3 A key component of the borrow check is the
4 [MIR type-check](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/index.html).
5 This check walks the MIR and does a complete "type check" -- the same
6 kind you might find in any other language. In the process of doing
7 this type-check, we also uncover the region constraints that apply to
8 the program.
9
10 TODO -- elaborate further? Maybe? :)
11
12 ## User types
13
14 At the start of MIR type-check, we replace all regions in the body with new unconstrained regions.
15 However, this would cause us to accept the following program:
16 ```rust
17 fn foo<'a>(x: &'a u32) {
18 let y: &'static u32 = x;
19 }
20 ```
21 By erasing the lifetimes in the type of `y` we no longer know that it is supposed to be `'static`,
22 ignoring the intentions of the user.
23
24 To deal with this we remember all places where the user explicitly mentioned a type during
25 HIR type-check as [`CanonicalUserTypeAnnotations`][annot].
26
27 There are two different annotations we care about:
28 - explicit type ascriptions, e.g. `let y: &'static u32` results in `UserType::Ty(&'static u32)`.
29 - explicit generic arguments, e.g. `x.foo<&'a u32, Vec<String>>`
30 results in `UserType::TypeOf(foo_def_id, [&'a u32, Vec<String>])`.
31
32 As we do not want the region inference from the HIR type-check to influence MIR typeck,
33 we store the user type right after lowering it from the HIR.
34 This means that it may still contain inference variables,
35 which is why we are using **canonical** user type annotations.
36 We replace all inference variables with existential bound variables instead.
37 Something like `let x: Vec<_>` would therefore result in `exists<T> UserType::Ty(Vec<T>)`.
38
39 A pattern like `let Foo(x): Foo<&'a u32>` has a user type `Foo<&'a u32>` but
40 the actual type of `x` should only be `&'a u32`. For this, we use a [`UserTypeProjection`][proj].
41
42 In the MIR, we deal with user types in two slightly different ways.
43
44 Given a MIR local corresponding to a variable in a pattern which has an explicit type annotation,
45 we require the type of that local to be equal to the type of the [`UserTypeProjection`][proj].
46 This is directly stored in the [`LocalDecl`][decl].
47
48 We also constrain the type of scrutinee expressions, e.g. the type of `x` in `let _: &'a u32 = x;`.
49 Here `T_x` only has to be a subtype of the user type, so we instead use
50 [`StatementKind::AscribeUserType`][stmt] for that.
51
52 Note that we do not directly use the user type as the MIR typechecker
53 doesn't really deal with type and const inference variables. We instead store the final
54 [`inferred_type`][inf] from the HIR type-checker. During MIR typeck, we then replace its regions
55 with new nll inference vars and relate it with the actual `UserType` to get the correct region
56 constraints again.
57
58 After the MIR type-check, all user type annotations get discarded, as they aren't needed anymore.
59
60 [annot]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.CanonicalUserTypeAnnotation.html
61 [proj]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.UserTypeProjection.html
62 [decl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.LocalDecl.html
63 [stmt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.StatementKind.html#variant.AscribeUserType
64 [inf]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.CanonicalUserTypeAnnotation.html#structfield.inferred_ty