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