]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/gather_locals.rs
Rollup merge of #78463 - varkor:placeholder-const, r=nikomatsakis
[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 use std::mem;
10
11 pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
12     fcx: &'a FnCtxt<'a, 'tcx>,
13     parent_id: hir::HirId,
14     // parameters are special cases of patterns, but we want to handle them as
15     // *distinct* cases. so track when we are hitting a pattern *within* an fn
16     // parameter.
17     outermost_fn_param_pat: bool,
18 }
19
20 impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
21     pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self {
22         Self { fcx, parent_id, outermost_fn_param_pat: false }
23     }
24
25     fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
26         match ty_opt {
27             None => {
28                 // Infer the variable's type.
29                 let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
30                     kind: TypeVariableOriginKind::TypeInference,
31                     span,
32                 });
33                 self.fcx
34                     .locals
35                     .borrow_mut()
36                     .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
37                 var_ty
38             }
39             Some(typ) => {
40                 // Take type that the user specified.
41                 self.fcx.locals.borrow_mut().insert(nid, typ);
42                 typ.revealed_ty
43             }
44         }
45     }
46 }
47
48 impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
49     type Map = intravisit::ErasedMap<'tcx>;
50
51     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
52         NestedVisitorMap::None
53     }
54
55     // Add explicitly-declared locals.
56     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
57         let local_ty = match local.ty {
58             Some(ref ty) => {
59                 let o_ty = self.fcx.to_ty(&ty);
60
61                 let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
62                     self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
63                 } else {
64                     o_ty
65                 };
66
67                 let c_ty = self
68                     .fcx
69                     .inh
70                     .infcx
71                     .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
72                 debug!(
73                     "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
74                     ty.hir_id, o_ty, revealed_ty, c_ty
75                 );
76                 self.fcx
77                     .typeck_results
78                     .borrow_mut()
79                     .user_provided_types_mut()
80                     .insert(ty.hir_id, c_ty);
81
82                 Some(LocalTy { decl_ty: o_ty, revealed_ty })
83             }
84             None => None,
85         };
86         self.assign(local.span, local.hir_id, local_ty);
87
88         debug!(
89             "local variable {:?} is assigned type {}",
90             local.pat,
91             self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
92         );
93         intravisit::walk_local(self, local);
94     }
95
96     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
97         let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, true);
98         intravisit::walk_param(self, param);
99         self.outermost_fn_param_pat = old_outermost_fn_param_pat;
100     }
101
102     // Add pattern bindings.
103     fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
104         if let PatKind::Binding(_, _, ident, _) = p.kind {
105             let var_ty = self.assign(p.span, p.hir_id, None);
106
107             if self.outermost_fn_param_pat {
108                 if !self.fcx.tcx.features().unsized_fn_params {
109                     self.fcx.require_type_is_sized(
110                         var_ty,
111                         p.span,
112                         traits::SizedArgumentType(Some(p.span)),
113                     );
114                 }
115             } else {
116                 if !self.fcx.tcx.features().unsized_locals {
117                     self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
118                 }
119             }
120
121             debug!(
122                 "pattern binding {} is assigned to {} with type {:?}",
123                 ident,
124                 self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
125                 var_ty
126             );
127         }
128         let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, false);
129         intravisit::walk_pat(self, p);
130         self.outermost_fn_param_pat = old_outermost_fn_param_pat;
131     }
132
133     // Don't descend into the bodies of nested closures.
134     fn visit_fn(
135         &mut self,
136         _: intravisit::FnKind<'tcx>,
137         _: &'tcx hir::FnDecl<'tcx>,
138         _: hir::BodyId,
139         _: Span,
140         _: hir::HirId,
141     ) {
142     }
143 }