1 use crate::check::{FnCtxt, LocalTy, UserType};
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;
8 use rustc_trait_selection::traits;
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
17 outermost_fn_param_pat: bool,
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 }
25 fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
28 // Infer the variable's type.
29 let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
30 kind: TypeVariableOriginKind::TypeInference,
36 .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
40 // Take type that the user specified.
41 self.fcx.locals.borrow_mut().insert(nid, typ);
48 impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
49 type Map = intravisit::ErasedMap<'tcx>;
51 fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
52 NestedVisitorMap::None
55 // Add explicitly-declared locals.
56 fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
57 let local_ty = match local.ty {
59 let o_ty = self.fcx.to_ty(&ty);
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)
68 self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(revealed_ty));
70 "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
71 ty.hir_id, o_ty, revealed_ty, c_ty
76 .user_provided_types_mut()
77 .insert(ty.hir_id, c_ty);
79 Some(LocalTy { decl_ty: o_ty, revealed_ty })
83 self.assign(local.span, local.hir_id, local_ty);
86 "local variable {:?} is assigned type {}",
88 self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
90 intravisit::walk_local(self, local);
93 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
94 let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, true);
95 intravisit::walk_param(self, param);
96 self.outermost_fn_param_pat = old_outermost_fn_param_pat;
99 // Add pattern bindings.
100 fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
101 if let PatKind::Binding(_, _, ident, _) = p.kind {
102 let var_ty = self.assign(p.span, p.hir_id, None);
104 if self.outermost_fn_param_pat {
105 if !self.fcx.tcx.features().unsized_fn_params {
106 self.fcx.require_type_is_sized(
109 traits::SizedArgumentType(Some(p.span)),
113 if !self.fcx.tcx.features().unsized_locals {
114 self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
119 "pattern binding {} is assigned to {} with type {:?}",
121 self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
125 let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, false);
126 intravisit::walk_pat(self, p);
127 self.outermost_fn_param_pat = old_outermost_fn_param_pat;
130 // Don't descend into the bodies of nested closures.
133 _: intravisit::FnKind<'tcx>,
134 _: &'tcx hir::FnDecl<'tcx>,