@@ -186,6 +186,139 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
186186    } 
187187} 
188188
189+ /// `path` is the AST path item naming the type of this struct. 
190+  /// `fields` is the field patterns of the struct  pattern. 
191+ /// `class_fields` describes the type of each field of the struct. 
192+ /// `class_id` is the ID of the struct. 
193+ /// `substitutions` are the type substitutions applied to this struct type 
194+ /// (e.g. K,V in HashMap<K,V>). 
195+ /// `etc` is true if the pattern said '...' and false otherwise. 
196+ fn  check_struct_pat_fields( pcx:  pat_ctxt, 
197+                            span:  span, 
198+                            path:  @ast:: path, 
199+                            fields:  ~[ ast:: field_pat] , 
200+                            class_fields:  ~[ ty:: field_ty] , 
201+                            class_id:  ast:: def_id, 
202+                            substitutions:  & ty:: substs, 
203+                            etc:  bool )  { 
204+     let  tcx = pcx. fcx. ccx. tcx; 
205+ 
206+     // Index the class fields. 
207+     let  field_map = std:: map:: HashMap ( ) ; 
208+     for  class_fields. eachi |i,  class_field| { 
209+         field_map. insert( class_field. ident,  i) ; 
210+     } 
211+ 
212+     // Typecheck each field. 
213+     let  found_fields = std:: map:: HashMap ( ) ; 
214+     for  fields. each |field| { 
215+         match  field_map. find( field. ident)  { 
216+             Some ( index)  => { 
217+                 let  class_field = class_fields[ index] ; 
218+                 let  field_type = ty:: lookup_field_type( tcx, 
219+                                                        class_id, 
220+                                                        class_field. id, 
221+                                                        substitutions) ; 
222+                 check_pat( pcx,  field. pat,  field_type) ; 
223+                 found_fields. insert( index,  ( ) ) ; 
224+             } 
225+             None  => { 
226+                 let  name = pprust:: path_to_str( path,  tcx. sess. intr( ) ) ; 
227+                 tcx. sess. span_err( span, 
228+                                   fmt!( "struct `%s` does not have a field 
229+                                         named `%s`" ,  name, 
230+                                        tcx. sess. str_of( field. ident) ) ) ; 
231+             } 
232+         } 
233+     } 
234+ 
235+     // Report an error if not all the fields were specified. 
236+     if  !etc { 
237+         for  class_fields. eachi |i,  field| { 
238+             if  found_fields. contains_key( i)  { 
239+                 loop ; 
240+             } 
241+             tcx. sess. span_err( span, 
242+                               fmt!( "pattern does not mention field `%s`" , 
243+                                    tcx. sess. str_of( field. ident) ) ) ; 
244+         } 
245+     } 
246+ } 
247+ 
248+ fn  check_struct_pat( pcx:  pat_ctxt,  pat_id:  ast:: node_id,  span:  span, 
249+                     expected:  ty:: t,  path:  @ast:: path, 
250+                     fields:  ~[ ast:: field_pat] ,  etc:  bool , 
251+                     class_id:  ast:: def_id,  substitutions:  & ty:: substs)  { 
252+     let  fcx = pcx. fcx; 
253+     let  tcx = pcx. fcx. ccx. tcx; 
254+ 
255+     let  class_fields = ty:: lookup_class_fields( tcx,  class_id) ; 
256+ 
257+     // Check to ensure that the struct is the one specified. 
258+     match  tcx. def_map. find( pat_id)  { 
259+         Some ( ast:: def_class( supplied_def_id) ) 
260+                 if  supplied_def_id == class_id => { 
261+             // OK. 
262+         } 
263+         Some ( ast:: def_class( * ) )  | Some ( ast:: def_variant( * ) )  => { 
264+             let  name = pprust:: path_to_str( path,  tcx. sess. intr( ) ) ; 
265+             tcx. sess. span_err( span, 
266+                               fmt!( "mismatched types: expected `%s` but \  
267+                                      found `%s`", 
268+                                    fcx. infcx( ) . ty_to_str( expected) , 
269+                                    name) ) ; 
270+         } 
271+         _ => { 
272+             tcx. sess. span_bug( span,  ~"resolve didn' t write in class"); 
273+         } 
274+     } 
275+ 
276+     // Forbid pattern-matching structs with destructors. 
277+     if ty::has_dtor(tcx, class_id) { 
278+         tcx.sess.span_err(span, ~" deconstructing struct  not allowed in \
279+                                   pattern ( it has a destructor) "); 
280+     } 
281+ 
282+     check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id, 
283+                             substitutions, etc); 
284+ } 
285+ 
286+ fn check_struct_like_enum_variant_pat(pcx: pat_ctxt, 
287+                                       pat_id: ast::node_id, 
288+                                       span: span, 
289+                                       expected: ty::t, 
290+                                       path: @ast::path, 
291+                                       fields: ~[ast::field_pat], 
292+                                       etc: bool, 
293+                                       enum_id: ast::def_id, 
294+                                       substitutions: &ty::substs) { 
295+     let fcx = pcx.fcx; 
296+     let tcx = pcx.fcx.ccx.tcx; 
297+ 
298+     // Find the variant that was specified. 
299+     match tcx.def_map.find(pat_id) { 
300+         Some(ast::def_variant(found_enum_id, variant_id)) 
301+                 if found_enum_id == enum_id => { 
302+             // Get the struct fields from this struct-like enum variant. 
303+             let class_fields = ty::lookup_class_fields(tcx, variant_id); 
304+ 
305+             check_struct_pat_fields(pcx, span, path, fields, class_fields, 
306+                                     variant_id, substitutions, etc); 
307+         } 
308+         Some(ast::def_class(*)) | Some(ast::def_variant(*)) => { 
309+             let name = pprust::path_to_str(path, tcx.sess.intr()); 
310+             tcx.sess.span_err(span, 
311+                               fmt!(" mismatched types:  expected `%s` but \
312+                                     found `%s`", 
313+                                    fcx. infcx( ) . ty_to_str( expected) , 
314+                                    name) ) ; 
315+         } 
316+         _ => { 
317+             tcx. sess. span_bug( span,  ~"resolve didn' t write in variant"); 
318+         } 
319+     } 
320+ } 
321+ 
189322// Pattern checking is top-down rather than bottom-up so that bindings get 
190323// their types immediately. 
191324fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { 
@@ -306,13 +439,16 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
306439      } 
307440      ast:: pat_struct( path,  fields,  etc)  => { 
308441        // Grab the class data that we care about. 
309-         let  class_fields,  class_id,  substitutions; 
310442        let  structure = structure_of( fcx,  pat. span,  expected) ; 
311443        match  structure { 
312444            ty:: ty_class( cid,  ref substs)  => { 
313-                 class_id = cid; 
314-                 substitutions = substs; 
315-                 class_fields = ty:: lookup_class_fields( tcx,  class_id) ; 
445+                 check_struct_pat( pcx,  pat. id,  pat. span,  expected,  path, 
446+                                  fields,  etc,  cid,  substs) ; 
447+             } 
448+             ty:: ty_enum( eid,  ref substs)  => { 
449+                 check_struct_like_enum_variant_pat( 
450+                     pcx,  pat. id,  pat. span,  expected,  path,  fields,  etc,  eid, 
451+                     substs) ; 
316452            } 
317453            _ => { 
318454                // XXX: This should not be fatal. 
@@ -323,72 +459,6 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
323459            } 
324460        } 
325461
326-         // Check to ensure that the struct is the one specified. 
327-         match  tcx. def_map. get( pat. id)  { 
328-             ast:: def_class( supplied_def_id) 
329-                     if  supplied_def_id == class_id => { 
330-                 // OK. 
331-             } 
332-             ast:: def_class( * )  => { 
333-                 let  name = pprust:: path_to_str( path,  tcx. sess. intr( ) ) ; 
334-                 tcx. sess. span_err( pat. span, 
335-                                   fmt!( "mismatched types: expected `%s` but \  
336-                                          found `%s`", 
337-                                        fcx. infcx( ) . ty_to_str( expected) , 
338-                                        name) ) ; 
339-             } 
340-             _ => { 
341-                 tcx. sess. span_bug( pat. span,  ~"resolve didn' t write in class"); 
342-             } 
343-         } 
344- 
345-         // Forbid pattern-matching structs with destructors. 
346-         if ty::has_dtor(tcx, class_id) { 
347-             tcx.sess.span_err(pat.span, ~" deconstructing struct  not allowed \
348-                                           in  pattern ( it has a destructor) "); 
349-         } 
350- 
351-         // Index the class fields. 
352-         let field_map = std::map::HashMap(); 
353-         for class_fields.eachi |i, class_field| { 
354-             field_map.insert(class_field.ident, i); 
355-         } 
356- 
357-         // Typecheck each field. 
358-         let found_fields = std::map::HashMap(); 
359-         for fields.each |field| { 
360-             match field_map.find(field.ident) { 
361-                 Some(index) => { 
362-                     let class_field = class_fields[index]; 
363-                     let field_type = ty::lookup_field_type(tcx, 
364-                                                            class_id, 
365-                                                            class_field.id, 
366-                                                            substitutions); 
367-                     check_pat(pcx, field.pat, field_type); 
368-                     found_fields.insert(index, ()); 
369-                 } 
370-                 None => { 
371-                     let name = pprust::path_to_str(path, tcx.sess.intr()); 
372-                     tcx.sess.span_err(pat.span, 
373-                                       fmt!(" struct  `%s` does not have a field
374-                                             named `%s`",  name, 
375-                                            tcx. sess. str_of( field. ident) ) ) ; 
376-                 } 
377-             } 
378-         } 
379- 
380-         // Report an error if not all the fields were specified. 
381-         if  !etc { 
382-             for  class_fields. eachi |i,  field| { 
383-                 if  found_fields. contains_key( i)  { 
384-                     loop ; 
385-                 } 
386-                 tcx. sess. span_err( pat. span, 
387-                                   fmt!( "pattern does not mention field `%s`" , 
388-                                        tcx. sess. str_of( field. ident) ) ) ; 
389-             } 
390-         } 
391- 
392462        // Finally, write in the type. 
393463        fcx. write_ty( pat. id,  expected) ; 
394464      } 
0 commit comments