@@ -55,6 +55,14 @@ impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> {
55
55
}
56
56
}
57
57
58
+ /// The `GatherLocalsVisitor` is responsible for initializing local variable types
59
+ /// in the [`ty::TypeckResults`] for all subpatterns in statements and expressions
60
+ /// like `let`, `match`, and params of function bodies. It also adds `Sized` bounds
61
+ /// for these types (with exceptions for unzied feature gates like `unsized_fn_params`).
62
+ ///
63
+ /// Failure to visit locals will cause an ICE in writeback when the local's type is
64
+ /// resolved. Visiting locals twice will ICE in the `GatherLocalsVisitor`, since it
65
+ /// will overwrite the type previously stored in the local.
58
66
pub ( super ) struct GatherLocalsVisitor < ' a , ' tcx > {
59
67
fcx : & ' a FnCtxt < ' a , ' tcx > ,
60
68
// parameters are special cases of patterns, but we want to handle them as
@@ -63,22 +71,50 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
63
71
outermost_fn_param_pat : Option < ( Span , HirId ) > ,
64
72
}
65
73
74
+ // N.B. additional `gather_*` functions should be careful to only walk the pattern
75
+ // for new expressions, since visiting sub-expressions or nested bodies may initialize
76
+ // locals which are not conceptually owned by the gathered statement or expression.
66
77
impl < ' a , ' tcx > GatherLocalsVisitor < ' a , ' tcx > {
67
- pub ( super ) fn new ( fcx : & ' a FnCtxt < ' a , ' tcx > ) -> Self {
68
- Self { fcx, outermost_fn_param_pat : None }
78
+ pub ( crate ) fn gather_from_local ( fcx : & ' a FnCtxt < ' a , ' tcx > , local : & ' tcx hir:: LetStmt < ' tcx > ) {
79
+ let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat : None } ;
80
+ visitor. declare ( local. into ( ) ) ;
81
+ visitor. visit_pat ( local. pat ) ;
82
+ }
83
+
84
+ pub ( crate ) fn gather_from_let_expr (
85
+ fcx : & ' a FnCtxt < ' a , ' tcx > ,
86
+ let_expr : & ' tcx hir:: LetExpr < ' tcx > ,
87
+ expr_hir_id : hir:: HirId ,
88
+ ) {
89
+ let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat : None } ;
90
+ visitor. declare ( ( let_expr, expr_hir_id) . into ( ) ) ;
91
+ visitor. visit_pat ( let_expr. pat ) ;
92
+ }
93
+
94
+ pub ( crate ) fn gather_from_param ( fcx : & ' a FnCtxt < ' a , ' tcx > , param : & ' tcx hir:: Param < ' tcx > ) {
95
+ let mut visitor = GatherLocalsVisitor {
96
+ fcx,
97
+ outermost_fn_param_pat : Some ( ( param. ty_span , param. hir_id ) ) ,
98
+ } ;
99
+ visitor. visit_pat ( param. pat ) ;
100
+ }
101
+
102
+ pub ( crate ) fn gather_from_arm ( fcx : & ' a FnCtxt < ' a , ' tcx > , local : & ' tcx hir:: Arm < ' tcx > ) {
103
+ let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat : None } ;
104
+ visitor. visit_pat ( local. pat ) ;
69
105
}
70
106
71
107
fn assign ( & mut self , span : Span , nid : HirId , ty_opt : Option < Ty < ' tcx > > ) -> Ty < ' tcx > {
72
108
match ty_opt {
73
109
None => {
74
110
// Infer the variable's type.
75
111
let var_ty = self . fcx . next_ty_var ( span) ;
76
- self . fcx . locals . borrow_mut ( ) . insert ( nid, var_ty) ;
112
+ assert_eq ! ( self . fcx. locals. borrow_mut( ) . insert( nid, var_ty) , None ) ;
77
113
var_ty
78
114
}
79
115
Some ( typ) => {
80
116
// Take type that the user specified.
81
- self . fcx . locals . borrow_mut ( ) . insert ( nid, typ) ;
117
+ assert_eq ! ( self . fcx. locals. borrow_mut( ) . insert( nid, typ) , None ) ;
82
118
typ
83
119
}
84
120
}
@@ -133,13 +169,6 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
133
169
intravisit:: walk_expr ( self , expr)
134
170
}
135
171
136
- fn visit_param ( & mut self , param : & ' tcx hir:: Param < ' tcx > ) {
137
- let old_outermost_fn_param_pat =
138
- self . outermost_fn_param_pat . replace ( ( param. ty_span , param. hir_id ) ) ;
139
- intravisit:: walk_param ( self , param) ;
140
- self . outermost_fn_param_pat = old_outermost_fn_param_pat;
141
- }
142
-
143
172
// Add pattern bindings.
144
173
fn visit_pat ( & mut self , p : & ' tcx hir:: Pat < ' tcx > ) {
145
174
if let PatKind :: Binding ( _, _, ident, _) = p. kind {
0 commit comments