@@ -4,7 +4,7 @@ use std::iter::repeat_with;
44
55use chalk_ir:: Mutability ;
66use hir_def:: {
7- expr:: { BindingAnnotation , Expr , Literal , Pat , PatId , RecordFieldPat } ,
7+ expr:: { BindingAnnotation , Expr , Literal , Pat , PatId } ,
88 path:: Path ,
99 type_ref:: ConstScalar ,
1010} ;
@@ -17,15 +17,20 @@ use crate::{
1717 TyKind ,
1818} ;
1919
20+ use super :: PatLike ;
21+
2022impl < ' a > InferenceContext < ' a > {
21- fn infer_tuple_struct_pat (
23+ /// Infers type for tuple struct pattern or its corresponding assignee expression.
24+ ///
25+ /// Ellipses found in the original pattern or expression must be filtered out.
26+ pub ( super ) fn infer_tuple_struct_pat_like < T : PatLike > (
2227 & mut self ,
2328 path : Option < & Path > ,
24- subpats : & [ PatId ] ,
2529 expected : & Ty ,
26- default_bm : BindingMode ,
27- id : PatId ,
30+ default_bm : T :: BindingMode ,
31+ id : T ,
2832 ellipsis : Option < usize > ,
33+ subs : & [ T ] ,
2934 ) -> Ty {
3035 let ( ty, def) = self . resolve_variant ( path, true ) ;
3136 let var_data = def. map ( |it| it. variant_data ( self . db . upcast ( ) ) ) ;
@@ -39,8 +44,8 @@ impl<'a> InferenceContext<'a> {
3944
4045 let field_tys = def. map ( |it| self . db . field_types ( it) ) . unwrap_or_default ( ) ;
4146 let ( pre, post) = match ellipsis {
42- Some ( idx) => subpats . split_at ( idx) ,
43- None => ( subpats , & [ ] [ ..] ) ,
47+ Some ( idx) => subs . split_at ( idx) ,
48+ None => ( subs , & [ ] [ ..] ) ,
4449 } ;
4550 let post_idx_offset = field_tys. iter ( ) . count ( ) . saturating_sub ( post. len ( ) ) ;
4651
@@ -54,22 +59,22 @@ impl<'a> InferenceContext<'a> {
5459 field_tys[ field] . clone ( ) . substitute ( Interner , & substs)
5560 } ) ;
5661 let expected_ty = self . normalize_associated_types_in ( expected_ty) ;
57- self . infer_pat ( subpat, & expected_ty, default_bm) ;
62+ T :: infer ( self , subpat, & expected_ty, default_bm) ;
5863 }
5964
6065 ty
6166 }
6267
63- fn infer_record_pat (
68+ /// Infers type for record pattern or its corresponding assignee expression.
69+ pub ( super ) fn infer_record_pat_like < T : PatLike > (
6470 & mut self ,
6571 path : Option < & Path > ,
66- subpats : & [ RecordFieldPat ] ,
6772 expected : & Ty ,
68- default_bm : BindingMode ,
69- id : PatId ,
73+ default_bm : T :: BindingMode ,
74+ id : T ,
75+ subs : impl Iterator < Item = ( Name , T ) > ,
7076 ) -> Ty {
7177 let ( ty, def) = self . resolve_variant ( path, false ) ;
72- let var_data = def. map ( |it| it. variant_data ( self . db . upcast ( ) ) ) ;
7378 if let Some ( variant) = def {
7479 self . write_variant_resolution ( id. into ( ) , variant) ;
7580 }
@@ -80,18 +85,64 @@ impl<'a> InferenceContext<'a> {
8085 ty. as_adt ( ) . map ( |( _, s) | s. clone ( ) ) . unwrap_or_else ( || Substitution :: empty ( Interner ) ) ;
8186
8287 let field_tys = def. map ( |it| self . db . field_types ( it) ) . unwrap_or_default ( ) ;
83- for subpat in subpats {
84- let matching_field = var_data. as_ref ( ) . and_then ( |it| it. field ( & subpat. name ) ) ;
85- let expected_ty = matching_field. map_or ( self . err_ty ( ) , |field| {
86- field_tys[ field] . clone ( ) . substitute ( Interner , & substs)
87- } ) ;
88+ let var_data = def. map ( |it| it. variant_data ( self . db . upcast ( ) ) ) ;
89+
90+ for ( name, inner) in subs {
91+ let expected_ty = var_data
92+ . as_ref ( )
93+ . and_then ( |it| it. field ( & name) )
94+ . map_or ( self . err_ty ( ) , |f| field_tys[ f] . clone ( ) . substitute ( Interner , & substs) ) ;
8895 let expected_ty = self . normalize_associated_types_in ( expected_ty) ;
89- self . infer_pat ( subpat. pat , & expected_ty, default_bm) ;
96+
97+ T :: infer ( self , inner, & expected_ty, default_bm) ;
9098 }
9199
92100 ty
93101 }
94102
103+ /// Infers type for tuple pattern or its corresponding assignee expression.
104+ ///
105+ /// Ellipses found in the original pattern or expression must be filtered out.
106+ pub ( super ) fn infer_tuple_pat_like < T : PatLike > (
107+ & mut self ,
108+ expected : & Ty ,
109+ default_bm : T :: BindingMode ,
110+ ellipsis : Option < usize > ,
111+ subs : & [ T ] ,
112+ ) -> Ty {
113+ let expectations = match expected. as_tuple ( ) {
114+ Some ( parameters) => & * parameters. as_slice ( Interner ) ,
115+ _ => & [ ] ,
116+ } ;
117+
118+ let ( ( pre, post) , n_uncovered_patterns) = match ellipsis {
119+ Some ( idx) => ( subs. split_at ( idx) , expectations. len ( ) . saturating_sub ( subs. len ( ) ) ) ,
120+ None => ( ( & subs[ ..] , & [ ] [ ..] ) , 0 ) ,
121+ } ;
122+ let mut expectations_iter = expectations
123+ . iter ( )
124+ . cloned ( )
125+ . map ( |a| a. assert_ty_ref ( Interner ) . clone ( ) )
126+ . chain ( repeat_with ( || self . table . new_type_var ( ) ) ) ;
127+
128+ let mut inner_tys = Vec :: with_capacity ( n_uncovered_patterns + subs. len ( ) ) ;
129+
130+ inner_tys. extend ( expectations_iter. by_ref ( ) . take ( n_uncovered_patterns + subs. len ( ) ) ) ;
131+
132+ // Process pre
133+ for ( ty, pat) in inner_tys. iter_mut ( ) . zip ( pre) {
134+ * ty = T :: infer ( self , * pat, ty, default_bm) ;
135+ }
136+
137+ // Process post
138+ for ( ty, pat) in inner_tys. iter_mut ( ) . skip ( pre. len ( ) + n_uncovered_patterns) . zip ( post) {
139+ * ty = T :: infer ( self , * pat, ty, default_bm) ;
140+ }
141+
142+ TyKind :: Tuple ( inner_tys. len ( ) , Substitution :: from_iter ( Interner , inner_tys) )
143+ . intern ( Interner )
144+ }
145+
95146 pub ( super ) fn infer_pat (
96147 & mut self ,
97148 pat : PatId ,
@@ -129,42 +180,7 @@ impl<'a> InferenceContext<'a> {
129180
130181 let ty = match & self . body [ pat] {
131182 Pat :: Tuple { args, ellipsis } => {
132- let expectations = match expected. as_tuple ( ) {
133- Some ( parameters) => & * parameters. as_slice ( Interner ) ,
134- _ => & [ ] ,
135- } ;
136-
137- let ( ( pre, post) , n_uncovered_patterns) = match ellipsis {
138- Some ( idx) => {
139- ( args. split_at ( * idx) , expectations. len ( ) . saturating_sub ( args. len ( ) ) )
140- }
141- None => ( ( & args[ ..] , & [ ] [ ..] ) , 0 ) ,
142- } ;
143- let mut expectations_iter = expectations
144- . iter ( )
145- . cloned ( )
146- . map ( |a| a. assert_ty_ref ( Interner ) . clone ( ) )
147- . chain ( repeat_with ( || self . table . new_type_var ( ) ) ) ;
148-
149- let mut inner_tys = Vec :: with_capacity ( n_uncovered_patterns + args. len ( ) ) ;
150-
151- inner_tys
152- . extend ( expectations_iter. by_ref ( ) . take ( n_uncovered_patterns + args. len ( ) ) ) ;
153-
154- // Process pre
155- for ( ty, pat) in inner_tys. iter_mut ( ) . zip ( pre) {
156- * ty = self . infer_pat ( * pat, ty, default_bm) ;
157- }
158-
159- // Process post
160- for ( ty, pat) in
161- inner_tys. iter_mut ( ) . skip ( pre. len ( ) + n_uncovered_patterns) . zip ( post)
162- {
163- * ty = self . infer_pat ( * pat, ty, default_bm) ;
164- }
165-
166- TyKind :: Tuple ( inner_tys. len ( ) , Substitution :: from_iter ( Interner , inner_tys) )
167- . intern ( Interner )
183+ self . infer_tuple_pat_like ( & expected, default_bm, * ellipsis, args)
168184 }
169185 Pat :: Or ( pats) => {
170186 if let Some ( ( first_pat, rest) ) = pats. split_first ( ) {
@@ -191,16 +207,18 @@ impl<'a> InferenceContext<'a> {
191207 let subty = self . infer_pat ( * pat, & expectation, default_bm) ;
192208 TyKind :: Ref ( mutability, static_lifetime ( ) , subty) . intern ( Interner )
193209 }
194- Pat :: TupleStruct { path : p, args : subpats, ellipsis } => self . infer_tuple_struct_pat (
195- p. as_deref ( ) ,
196- subpats,
197- & expected,
198- default_bm,
199- pat,
200- * ellipsis,
201- ) ,
210+ Pat :: TupleStruct { path : p, args : subpats, ellipsis } => self
211+ . infer_tuple_struct_pat_like (
212+ p. as_deref ( ) ,
213+ & expected,
214+ default_bm,
215+ pat,
216+ * ellipsis,
217+ subpats,
218+ ) ,
202219 Pat :: Record { path : p, args : fields, ellipsis : _ } => {
203- self . infer_record_pat ( p. as_deref ( ) , fields, & expected, default_bm, pat)
220+ let subs = fields. iter ( ) . map ( |f| ( f. name . clone ( ) , f. pat ) ) ;
221+ self . infer_record_pat_like ( p. as_deref ( ) , & expected, default_bm, pat. into ( ) , subs)
204222 }
205223 Pat :: Path ( path) => {
206224 // FIXME use correct resolver for the surrounding expression
0 commit comments