@@ -8,3 +8,57 @@ this type-check, we also uncover the region constraints that apply to
8
8
the program.
9
9
10
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
0 commit comments