@@ -55,6 +55,14 @@ impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> {
5555 }
5656}
5757
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 unsized 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.
5866pub ( super ) struct GatherLocalsVisitor < ' a , ' tcx > {
5967 fcx : & ' a FnCtxt < ' a , ' tcx > ,
6068 // parameters are special cases of patterns, but we want to handle them as
@@ -63,22 +71,50 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
6371 outermost_fn_param_pat : Option < ( Span , HirId ) > ,
6472}
6573
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.
6677impl < ' 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 ) ;
69105 }
70106
71107 fn assign ( & mut self , span : Span , nid : HirId , ty_opt : Option < Ty < ' tcx > > ) -> Ty < ' tcx > {
72108 match ty_opt {
73109 None => {
74110 // Infer the variable's type.
75111 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 ) ;
77113 var_ty
78114 }
79115 Some ( typ) => {
80116 // 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 ) ;
82118 typ
83119 }
84120 }
@@ -133,13 +169,6 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
133169 intravisit:: walk_expr ( self , expr)
134170 }
135171
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-
143172 // Add pattern bindings.
144173 fn visit_pat ( & mut self , p : & ' tcx hir:: Pat < ' tcx > ) {
145174 if let PatKind :: Binding ( _, _, ident, _) = p. kind {
0 commit comments