@@ -186,6 +186,139 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
186
186
}
187
187
}
188
188
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
+
189
322
// Pattern checking is top-down rather than bottom-up so that bindings get
190
323
// their types immediately.
191
324
fn 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) {
306
439
}
307
440
ast:: pat_struct( path, fields, etc) => {
308
441
// Grab the class data that we care about.
309
- let class_fields, class_id, substitutions;
310
442
let structure = structure_of( fcx, pat. span, expected) ;
311
443
match structure {
312
444
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) ;
316
452
}
317
453
_ => {
318
454
// XXX: This should not be fatal.
@@ -323,72 +459,6 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
323
459
}
324
460
}
325
461
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
-
392
462
// Finally, write in the type.
393
463
fcx. write_ty( pat. id, expected) ;
394
464
}
0 commit comments