@@ -163,9 +163,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
163
163
enum AdjustMode {
164
164
/// Peel off all immediate reference types.
165
165
Peel ,
166
- /// Reset binding mode to the initial mode.
167
- /// Used for destructuring assignment, where we don't want any match ergonomics.
168
- Reset ,
169
166
/// Pass on the input binding mode and expected type.
170
167
Pass ,
171
168
}
@@ -321,77 +318,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
321
318
/// Conversely, inside this module, `check_pat_top` should never be used.
322
319
#[ instrument( level = "debug" , skip( self , pat_info) ) ]
323
320
fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
324
- let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
325
-
326
- let path_res = match pat. kind {
321
+ let opt_path_res = match pat. kind {
327
322
PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
328
323
Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath, * hir_id, * span) )
329
324
}
330
325
_ => None ,
331
326
} ;
332
- let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
333
- let ( expected, binding_mode, max_ref_mutbl) =
334
- self . calc_default_binding_mode ( pat, expected, binding_mode, adjust_mode, max_ref_mutbl) ;
335
- let pat_info = PatInfo {
336
- binding_mode,
337
- max_ref_mutbl,
338
- top_info : ti,
339
- decl_origin : pat_info. decl_origin ,
340
- current_depth : current_depth + 1 ,
341
- } ;
342
-
343
- let ty = match pat. kind {
344
- PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
345
- // We allow any type here; we ensure that the type is uninhabited during match checking.
346
- PatKind :: Never => expected,
347
- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
348
- let ty = self . check_pat_path (
349
- * hir_id,
350
- pat. hir_id ,
351
- * span,
352
- qpath,
353
- path_res. unwrap ( ) ,
354
- expected,
355
- & pat_info. top_info ,
356
- ) ;
357
- self . write_ty ( * hir_id, ty) ;
358
- ty
359
- }
360
- PatKind :: Expr ( lt) => self . check_pat_lit ( pat. span , lt, expected, & pat_info. top_info ) ,
361
- PatKind :: Range ( lhs, rhs, _) => {
362
- self . check_pat_range ( pat. span , lhs, rhs, expected, & pat_info. top_info )
363
- }
364
- PatKind :: Binding ( ba, var_id, ident, sub) => {
365
- self . check_pat_ident ( pat, ba, var_id, ident, sub, expected, pat_info)
366
- }
367
- PatKind :: TupleStruct ( ref qpath, subpats, ddpos) => {
368
- self . check_pat_tuple_struct ( pat, qpath, subpats, ddpos, expected, pat_info)
369
- }
370
- PatKind :: Struct ( ref qpath, fields, has_rest_pat) => {
371
- self . check_pat_struct ( pat, qpath, fields, has_rest_pat, expected, pat_info)
372
- }
373
- PatKind :: Guard ( pat, cond) => {
374
- self . check_pat ( pat, expected, pat_info) ;
375
- self . check_expr_has_type_or_error ( cond, self . tcx . types . bool , |_| { } ) ;
376
- expected
377
- }
378
- PatKind :: Or ( pats) => {
379
- for pat in pats {
380
- self . check_pat ( pat, expected, pat_info) ;
381
- }
382
- expected
383
- }
384
- PatKind :: Tuple ( elements, ddpos) => {
385
- self . check_pat_tuple ( pat. span , elements, ddpos, expected, pat_info)
386
- }
387
- PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
388
- PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
389
- PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
390
- PatKind :: Slice ( before, slice, after) => {
391
- self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
392
- }
393
- } ;
394
-
327
+ let adjust_mode = self . calc_adjust_mode ( pat, opt_path_res. map ( |( res, ..) | res) ) ;
328
+ let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
395
329
self . write_ty ( pat. hir_id , ty) ;
396
330
397
331
// (note_1): In most of the cases where (note_1) is referenced
@@ -437,39 +371,133 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437
371
// `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
438
372
}
439
373
440
- /// Compute the new expected type and default binding mode from the old ones
441
- /// as well as the pattern form we are currently checking.
442
- fn calc_default_binding_mode (
374
+ // Helper to avoid resolving the same path pattern several times.
375
+ fn check_pat_inner (
443
376
& self ,
444
377
pat : & ' tcx Pat < ' tcx > ,
445
- expected : Ty < ' tcx > ,
446
- def_br : ByRef ,
378
+ opt_path_res : Option < ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) > ,
447
379
adjust_mode : AdjustMode ,
448
- max_ref_mutbl : MutblCap ,
449
- ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
380
+ expected : Ty < ' tcx > ,
381
+ pat_info : PatInfo < ' tcx > ,
382
+ ) -> Ty < ' tcx > {
450
383
#[ cfg( debug_assertions) ]
451
- if def_br == ByRef :: Yes ( Mutability :: Mut )
452
- && max_ref_mutbl != MutblCap :: Mut
384
+ if pat_info . binding_mode == ByRef :: Yes ( Mutability :: Mut )
385
+ && pat_info . max_ref_mutbl != MutblCap :: Mut
453
386
&& self . downgrade_mut_inside_shared ( )
454
387
{
455
388
span_bug ! ( pat. span, "Pattern mutability cap violated!" ) ;
456
389
}
457
- match adjust_mode {
458
- AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl) ,
459
- AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut ) ,
460
- AdjustMode :: Peel => self . peel_off_references ( pat, expected, def_br, max_ref_mutbl) ,
390
+
391
+ // Resolve type if needed.
392
+ let expected = if let AdjustMode :: Peel = adjust_mode
393
+ && pat. default_binding_modes
394
+ {
395
+ self . try_structurally_resolve_type ( pat. span , expected)
396
+ } else {
397
+ expected
398
+ } ;
399
+ let old_pat_info = pat_info;
400
+ let pat_info = PatInfo { current_depth : old_pat_info. current_depth + 1 , ..old_pat_info } ;
401
+
402
+ match pat. kind {
403
+ // Peel off a `&` or `&mut` from the scrutinee type. See the examples in
404
+ // `tests/ui/rfcs/rfc-2005-default-binding-mode`.
405
+ _ if let AdjustMode :: Peel = adjust_mode
406
+ && pat. default_binding_modes
407
+ && let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) =>
408
+ {
409
+ debug ! ( "inspecting {:?}" , expected) ;
410
+
411
+ debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
412
+ // Preserve the reference type. We'll need it later during THIR lowering.
413
+ self . typeck_results
414
+ . borrow_mut ( )
415
+ . pat_adjustments_mut ( )
416
+ . entry ( pat. hir_id )
417
+ . or_default ( )
418
+ . push ( expected) ;
419
+
420
+ let mut binding_mode = ByRef :: Yes ( match pat_info. binding_mode {
421
+ // If default binding mode is by value, make it `ref` or `ref mut`
422
+ // (depending on whether we observe `&` or `&mut`).
423
+ ByRef :: No |
424
+ // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
425
+ ByRef :: Yes ( Mutability :: Mut ) => inner_mutability,
426
+ // Once a `ref`, always a `ref`.
427
+ // This is because a `& &mut` cannot mutate the underlying value.
428
+ ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
429
+ } ) ;
430
+
431
+ let mut max_ref_mutbl = pat_info. max_ref_mutbl ;
432
+ if self . downgrade_mut_inside_shared ( ) {
433
+ binding_mode = binding_mode. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
434
+ }
435
+ if binding_mode == ByRef :: Yes ( Mutability :: Not ) {
436
+ max_ref_mutbl = MutblCap :: Not ;
437
+ }
438
+ debug ! ( "default binding mode is now {:?}" , binding_mode) ;
439
+
440
+ // Use the old pat info to keep `current_depth` to its old value.
441
+ let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info } ;
442
+ // Recurse with the new expected type.
443
+ self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
444
+ }
445
+ PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
446
+ // We allow any type here; we ensure that the type is uninhabited during match checking.
447
+ PatKind :: Never => expected,
448
+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
449
+ let ty = self . check_pat_path (
450
+ * hir_id,
451
+ pat. hir_id ,
452
+ * span,
453
+ qpath,
454
+ opt_path_res. unwrap ( ) ,
455
+ expected,
456
+ & pat_info. top_info ,
457
+ ) ;
458
+ self . write_ty ( * hir_id, ty) ;
459
+ ty
460
+ }
461
+ PatKind :: Expr ( lt) => self . check_pat_lit ( pat. span , lt, expected, & pat_info. top_info ) ,
462
+ PatKind :: Range ( lhs, rhs, _) => {
463
+ self . check_pat_range ( pat. span , lhs, rhs, expected, & pat_info. top_info )
464
+ }
465
+ PatKind :: Binding ( ba, var_id, ident, sub) => {
466
+ self . check_pat_ident ( pat, ba, var_id, ident, sub, expected, pat_info)
467
+ }
468
+ PatKind :: TupleStruct ( ref qpath, subpats, ddpos) => {
469
+ self . check_pat_tuple_struct ( pat, qpath, subpats, ddpos, expected, pat_info)
470
+ }
471
+ PatKind :: Struct ( ref qpath, fields, has_rest_pat) => {
472
+ self . check_pat_struct ( pat, qpath, fields, has_rest_pat, expected, pat_info)
473
+ }
474
+ PatKind :: Guard ( pat, cond) => {
475
+ self . check_pat ( pat, expected, pat_info) ;
476
+ self . check_expr_has_type_or_error ( cond, self . tcx . types . bool , |_| { } ) ;
477
+ expected
478
+ }
479
+ PatKind :: Or ( pats) => {
480
+ for pat in pats {
481
+ self . check_pat ( pat, expected, pat_info) ;
482
+ }
483
+ expected
484
+ }
485
+ PatKind :: Tuple ( elements, ddpos) => {
486
+ self . check_pat_tuple ( pat. span , elements, ddpos, expected, pat_info)
487
+ }
488
+ PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
489
+ PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
490
+ PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
491
+ PatKind :: Slice ( before, slice, after) => {
492
+ self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
493
+ }
461
494
}
462
495
}
463
496
464
497
/// How should the binding mode and expected type be adjusted?
465
498
///
466
499
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
467
500
fn calc_adjust_mode ( & self , pat : & ' tcx Pat < ' tcx > , opt_path_res : Option < Res > ) -> AdjustMode {
468
- // When we perform destructuring assignment, we disable default match bindings, which are
469
- // unintuitive in this context.
470
- if !pat. default_binding_modes {
471
- return AdjustMode :: Reset ;
472
- }
473
501
match & pat. kind {
474
502
// Type checking these product-like types successfully always require
475
503
// that the expected type be of those types and not reference types.
@@ -526,64 +554,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
526
554
}
527
555
}
528
556
529
- /// Peel off as many immediately nested `& mut?` from the expected type as possible
530
- /// and return the new expected type and binding default binding mode.
531
- /// The adjustments vector, if non-empty is stored in a table.
532
- fn peel_off_references (
533
- & self ,
534
- pat : & ' tcx Pat < ' tcx > ,
535
- expected : Ty < ' tcx > ,
536
- mut def_br : ByRef ,
537
- mut max_ref_mutbl : MutblCap ,
538
- ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
539
- let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
540
- // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
541
- // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
542
- // the `Some(5)` which is not of type Ref.
543
- //
544
- // For each ampersand peeled off, update the binding mode and push the original
545
- // type into the adjustments vector.
546
- //
547
- // See the examples in `ui/match-defbm*.rs`.
548
- let mut pat_adjustments = vec ! [ ] ;
549
- while let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
550
- debug ! ( "inspecting {:?}" , expected) ;
551
-
552
- debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
553
- // Preserve the reference type. We'll need it later during THIR lowering.
554
- pat_adjustments. push ( expected) ;
555
-
556
- expected = self . try_structurally_resolve_type ( pat. span , inner_ty) ;
557
- def_br = ByRef :: Yes ( match def_br {
558
- // If default binding mode is by value, make it `ref` or `ref mut`
559
- // (depending on whether we observe `&` or `&mut`).
560
- ByRef :: No |
561
- // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
562
- ByRef :: Yes ( Mutability :: Mut ) => inner_mutability,
563
- // Once a `ref`, always a `ref`.
564
- // This is because a `& &mut` cannot mutate the underlying value.
565
- ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
566
- } ) ;
567
- }
568
-
569
- if self . downgrade_mut_inside_shared ( ) {
570
- def_br = def_br. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
571
- }
572
- if def_br == ByRef :: Yes ( Mutability :: Not ) {
573
- max_ref_mutbl = MutblCap :: Not ;
574
- }
575
-
576
- if !pat_adjustments. is_empty ( ) {
577
- debug ! ( "default binding mode is now {:?}" , def_br) ;
578
- self . typeck_results
579
- . borrow_mut ( )
580
- . pat_adjustments_mut ( )
581
- . insert ( pat. hir_id , pat_adjustments) ;
582
- }
583
-
584
- ( expected, def_br, max_ref_mutbl)
585
- }
586
-
587
557
fn check_pat_expr_unadjusted ( & self , lt : & ' tcx hir:: PatExpr < ' tcx > ) -> Ty < ' tcx > {
588
558
let ty = match & lt. kind {
589
559
rustc_hir:: PatExprKind :: Lit { lit, negated } => {
0 commit comments