]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
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 | parent_id: hir::HirId, | |
13 | } | |
14 | ||
15 | impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { | |
16 | pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self { | |
17 | Self { fcx, parent_id } | |
18 | } | |
19 | ||
20 | fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> { | |
21 | match ty_opt { | |
22 | None => { | |
23 | // Infer the variable's type. | |
24 | let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { | |
25 | kind: TypeVariableOriginKind::TypeInference, | |
26 | span, | |
27 | }); | |
28 | self.fcx | |
29 | .locals | |
30 | .borrow_mut() | |
31 | .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); | |
32 | var_ty | |
33 | } | |
34 | Some(typ) => { | |
35 | // Take type that the user specified. | |
36 | self.fcx.locals.borrow_mut().insert(nid, typ); | |
37 | typ.revealed_ty | |
38 | } | |
39 | } | |
40 | } | |
41 | } | |
42 | ||
43 | impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { | |
44 | type Map = intravisit::ErasedMap<'tcx>; | |
45 | ||
46 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { | |
47 | NestedVisitorMap::None | |
48 | } | |
49 | ||
50 | // Add explicitly-declared locals. | |
51 | fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { | |
52 | let local_ty = match local.ty { | |
53 | Some(ref ty) => { | |
54 | let o_ty = self.fcx.to_ty(&ty); | |
55 | ||
56 | let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { | |
57 | self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) | |
58 | } else { | |
59 | o_ty | |
60 | }; | |
61 | ||
62 | let c_ty = self | |
63 | .fcx | |
64 | .inh | |
65 | .infcx | |
66 | .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); | |
67 | debug!( | |
68 | "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", | |
69 | ty.hir_id, o_ty, revealed_ty, c_ty | |
70 | ); | |
71 | self.fcx | |
72 | .typeck_results | |
73 | .borrow_mut() | |
74 | .user_provided_types_mut() | |
75 | .insert(ty.hir_id, c_ty); | |
76 | ||
77 | Some(LocalTy { decl_ty: o_ty, revealed_ty }) | |
78 | } | |
79 | None => None, | |
80 | }; | |
81 | self.assign(local.span, local.hir_id, local_ty); | |
82 | ||
83 | debug!( | |
84 | "local variable {:?} is assigned type {}", | |
85 | local.pat, | |
86 | self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) | |
87 | ); | |
88 | intravisit::walk_local(self, local); | |
89 | } | |
90 | ||
91 | // Add pattern bindings. | |
92 | fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { | |
93 | if let PatKind::Binding(_, _, ident, _) = p.kind { | |
94 | let var_ty = self.assign(p.span, p.hir_id, None); | |
95 | ||
96 | if !self.fcx.tcx.features().unsized_locals { | |
97 | self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); | |
98 | } | |
99 | ||
100 | debug!( | |
101 | "pattern binding {} is assigned to {} with type {:?}", | |
102 | ident, | |
103 | self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), | |
104 | var_ty | |
105 | ); | |
106 | } | |
107 | intravisit::walk_pat(self, p); | |
108 | } | |
109 | ||
110 | // Don't descend into the bodies of nested closures. | |
111 | fn visit_fn( | |
112 | &mut self, | |
113 | _: intravisit::FnKind<'tcx>, | |
114 | _: &'tcx hir::FnDecl<'tcx>, | |
115 | _: hir::BodyId, | |
116 | _: Span, | |
117 | _: hir::HirId, | |
118 | ) { | |
119 | } | |
120 | } |