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