]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | use crate::{FnCtxt, LocalTy}; |
1b1a35ee | 2 | use rustc_hir as hir; |
5099ac24 | 3 | use rustc_hir::intravisit::{self, Visitor}; |
1b1a35ee XL |
4 | use rustc_hir::PatKind; |
5 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
6 | use rustc_middle::ty::Ty; | |
2b03887a | 7 | use rustc_middle::ty::UserType; |
136023e0 | 8 | use rustc_span::Span; |
1b1a35ee XL |
9 | use rustc_trait_selection::traits; |
10 | ||
a2a8927a XL |
11 | /// A declaration is an abstraction of [hir::Local] and [hir::Let]. |
12 | /// | |
13 | /// It must have a hir_id, as this is how we connect gather_locals to the check functions. | |
14 | pub(super) struct Declaration<'a> { | |
15 | pub hir_id: hir::HirId, | |
16 | pub pat: &'a hir::Pat<'a>, | |
17 | pub ty: Option<&'a hir::Ty<'a>>, | |
18 | pub span: Span, | |
19 | pub init: Option<&'a hir::Expr<'a>>, | |
064997fb | 20 | pub els: Option<&'a hir::Block<'a>>, |
a2a8927a XL |
21 | } |
22 | ||
23 | impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { | |
24 | fn from(local: &'a hir::Local<'a>) -> Self { | |
064997fb FG |
25 | let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; |
26 | Declaration { hir_id, pat, ty, span, init, els } | |
a2a8927a XL |
27 | } |
28 | } | |
29 | ||
30 | impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { | |
31 | fn from(let_expr: &'a hir::Let<'a>) -> Self { | |
32 | let hir::Let { hir_id, pat, ty, span, init } = *let_expr; | |
064997fb | 33 | Declaration { hir_id, pat, ty, span, init: Some(init), els: None } |
a2a8927a XL |
34 | } |
35 | } | |
36 | ||
1b1a35ee XL |
37 | pub(super) struct GatherLocalsVisitor<'a, 'tcx> { |
38 | fcx: &'a FnCtxt<'a, 'tcx>, | |
29967ef6 XL |
39 | // parameters are special cases of patterns, but we want to handle them as |
40 | // *distinct* cases. so track when we are hitting a pattern *within* an fn | |
41 | // parameter. | |
cdc7bbd5 | 42 | outermost_fn_param_pat: Option<Span>, |
1b1a35ee XL |
43 | } |
44 | ||
45 | impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { | |
136023e0 XL |
46 | pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>) -> Self { |
47 | Self { fcx, outermost_fn_param_pat: None } | |
1b1a35ee XL |
48 | } |
49 | ||
50 | fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> { | |
51 | match ty_opt { | |
52 | None => { | |
53 | // Infer the variable's type. | |
54 | let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { | |
55 | kind: TypeVariableOriginKind::TypeInference, | |
56 | span, | |
57 | }); | |
58 | self.fcx | |
59 | .locals | |
60 | .borrow_mut() | |
61 | .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); | |
62 | var_ty | |
63 | } | |
64 | Some(typ) => { | |
65 | // Take type that the user specified. | |
66 | self.fcx.locals.borrow_mut().insert(nid, typ); | |
67 | typ.revealed_ty | |
68 | } | |
69 | } | |
70 | } | |
1b1a35ee | 71 | |
a2a8927a XL |
72 | /// Allocates a [LocalTy] for a declaration, which may have a type annotation. If it does have |
73 | /// a type annotation, then the LocalTy stored will be the resolved type. This may be found | |
74 | /// again during type checking by querying [FnCtxt::local_ty] for the same hir_id. | |
75 | fn declare(&mut self, decl: Declaration<'tcx>) { | |
76 | let local_ty = match decl.ty { | |
1b1a35ee XL |
77 | Some(ref ty) => { |
78 | let o_ty = self.fcx.to_ty(&ty); | |
79 | ||
9c376795 FG |
80 | let c_ty = |
81 | self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw)); | |
136023e0 | 82 | debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); |
1b1a35ee XL |
83 | self.fcx |
84 | .typeck_results | |
85 | .borrow_mut() | |
86 | .user_provided_types_mut() | |
87 | .insert(ty.hir_id, c_ty); | |
88 | ||
9c376795 | 89 | Some(LocalTy { decl_ty: o_ty.normalized, revealed_ty: o_ty.normalized }) |
1b1a35ee XL |
90 | } |
91 | None => None, | |
92 | }; | |
a2a8927a | 93 | self.assign(decl.span, decl.hir_id, local_ty); |
1b1a35ee XL |
94 | |
95 | debug!( | |
96 | "local variable {:?} is assigned type {}", | |
a2a8927a | 97 | decl.pat, |
5099ac24 | 98 | self.fcx.ty_to_string(self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty) |
1b1a35ee | 99 | ); |
a2a8927a XL |
100 | } |
101 | } | |
102 | ||
103 | impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { | |
a2a8927a XL |
104 | // Add explicitly-declared locals. |
105 | fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { | |
106 | self.declare(local.into()); | |
064997fb | 107 | intravisit::walk_local(self, local) |
1b1a35ee XL |
108 | } |
109 | ||
a2a8927a XL |
110 | fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { |
111 | self.declare(let_expr.into()); | |
112 | intravisit::walk_let_expr(self, let_expr); | |
113 | } | |
114 | ||
29967ef6 | 115 | fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { |
cdc7bbd5 | 116 | let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span); |
29967ef6 XL |
117 | intravisit::walk_param(self, param); |
118 | self.outermost_fn_param_pat = old_outermost_fn_param_pat; | |
119 | } | |
120 | ||
1b1a35ee XL |
121 | // Add pattern bindings. |
122 | fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { | |
123 | if let PatKind::Binding(_, _, ident, _) = p.kind { | |
124 | let var_ty = self.assign(p.span, p.hir_id, None); | |
125 | ||
cdc7bbd5 | 126 | if let Some(ty_span) = self.outermost_fn_param_pat { |
29967ef6 XL |
127 | if !self.fcx.tcx.features().unsized_fn_params { |
128 | self.fcx.require_type_is_sized( | |
129 | var_ty, | |
130 | p.span, | |
cdc7bbd5 | 131 | traits::SizedArgumentType(Some(ty_span)), |
29967ef6 XL |
132 | ); |
133 | } | |
134 | } else { | |
135 | if !self.fcx.tcx.features().unsized_locals { | |
136 | self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); | |
137 | } | |
1b1a35ee XL |
138 | } |
139 | ||
140 | debug!( | |
141 | "pattern binding {} is assigned to {} with type {:?}", | |
142 | ident, | |
5099ac24 | 143 | self.fcx.ty_to_string(self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), |
1b1a35ee XL |
144 | var_ty |
145 | ); | |
146 | } | |
cdc7bbd5 | 147 | let old_outermost_fn_param_pat = self.outermost_fn_param_pat.take(); |
1b1a35ee | 148 | intravisit::walk_pat(self, p); |
29967ef6 | 149 | self.outermost_fn_param_pat = old_outermost_fn_param_pat; |
1b1a35ee XL |
150 | } |
151 | ||
152 | // Don't descend into the bodies of nested closures. | |
153 | fn visit_fn( | |
154 | &mut self, | |
155 | _: intravisit::FnKind<'tcx>, | |
156 | _: &'tcx hir::FnDecl<'tcx>, | |
157 | _: hir::BodyId, | |
158 | _: Span, | |
159 | _: hir::HirId, | |
160 | ) { | |
161 | } | |
162 | } |