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