]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/gather_locals.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / gather_locals.rs
CommitLineData
1b1a35ee
XL
1use crate::check::{FnCtxt, LocalTy, UserType};
2use rustc_hir as hir;
5099ac24 3use rustc_hir::intravisit::{self, Visitor};
1b1a35ee
XL
4use rustc_hir::PatKind;
5use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
6use rustc_middle::ty::Ty;
136023e0 7use rustc_span::Span;
1b1a35ee
XL
8use 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.
13pub(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
22impl<'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
29impl<'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
36pub(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
44impl<'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
101impl<'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}