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