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