@@ -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
}
@@ -322,6 +319,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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
321
let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
322
+ #[ cfg( debug_assertions) ]
323
+ if binding_mode == ByRef :: Yes ( Mutability :: Mut )
324
+ && max_ref_mutbl != MutblCap :: Mut
325
+ && self . downgrade_mut_inside_shared ( )
326
+ {
327
+ span_bug ! ( pat. span, "Pattern mutability cap violated!" ) ;
328
+ }
325
329
326
330
let path_res = match pat. kind {
327
331
PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
@@ -330,8 +334,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
330
334
_ => None ,
331
335
} ;
332
336
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) ;
337
+ let ( expected, binding_mode, max_ref_mutbl) = match adjust_mode {
338
+ // When we perform destructuring assignment, we disable default match bindings, which
339
+ // are unintuitive in this context.
340
+ _ if !pat. default_binding_modes => ( expected, ByRef :: No , MutblCap :: Mut ) ,
341
+ AdjustMode :: Pass => ( expected, binding_mode, max_ref_mutbl) ,
342
+ // Peel off as many immediately nested `& mut?` from the expected type as possible
343
+ // and return the new expected type and binding default binding mode.
344
+ // The adjustments vector, if non-empty is stored in a table.
345
+ AdjustMode :: Peel => {
346
+ let mut binding_mode = binding_mode;
347
+ let mut max_ref_mutbl = max_ref_mutbl;
348
+ let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
349
+ // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
350
+ // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
351
+ // the `Some(5)` which is not of type Ref.
352
+ //
353
+ // For each ampersand peeled off, update the binding mode and push the original
354
+ // type into the adjustments vector.
355
+ //
356
+ // See the examples in `ui/match-defbm*.rs`.
357
+ let mut pat_adjustments = vec ! [ ] ;
358
+ while let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
359
+ debug ! ( "inspecting {:?}" , expected) ;
360
+
361
+ debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
362
+ // Preserve the reference type. We'll need it later during THIR lowering.
363
+ pat_adjustments. push ( expected) ;
364
+
365
+ expected = self . try_structurally_resolve_type ( pat. span , inner_ty) ;
366
+ binding_mode = ByRef :: Yes ( match binding_mode {
367
+ // If default binding mode is by value, make it `ref` or `ref mut`
368
+ // (depending on whether we observe `&` or `&mut`).
369
+ ByRef :: No |
370
+ // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
371
+ ByRef :: Yes ( Mutability :: Mut ) => inner_mutability,
372
+ // Once a `ref`, always a `ref`.
373
+ // This is because a `& &mut` cannot mutate the underlying value.
374
+ ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
375
+ } ) ;
376
+ }
377
+
378
+ if self . downgrade_mut_inside_shared ( ) {
379
+ binding_mode = binding_mode. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
380
+ }
381
+ if binding_mode == ByRef :: Yes ( Mutability :: Not ) {
382
+ max_ref_mutbl = MutblCap :: Not ;
383
+ }
384
+
385
+ if !pat_adjustments. is_empty ( ) {
386
+ debug ! ( "default binding mode is now {:?}" , binding_mode) ;
387
+ self . typeck_results
388
+ . borrow_mut ( )
389
+ . pat_adjustments_mut ( )
390
+ . insert ( pat. hir_id , pat_adjustments) ;
391
+ }
392
+
393
+ ( expected, binding_mode, max_ref_mutbl)
394
+ }
395
+ } ;
335
396
let pat_info = PatInfo {
336
397
binding_mode,
337
398
max_ref_mutbl,
@@ -437,39 +498,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437
498
// `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
438
499
}
439
500
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 (
443
- & self ,
444
- pat : & ' tcx Pat < ' tcx > ,
445
- expected : Ty < ' tcx > ,
446
- def_br : ByRef ,
447
- adjust_mode : AdjustMode ,
448
- max_ref_mutbl : MutblCap ,
449
- ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
450
- #[ cfg( debug_assertions) ]
451
- if def_br == ByRef :: Yes ( Mutability :: Mut )
452
- && max_ref_mutbl != MutblCap :: Mut
453
- && self . downgrade_mut_inside_shared ( )
454
- {
455
- span_bug ! ( pat. span, "Pattern mutability cap violated!" ) ;
456
- }
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) ,
461
- }
462
- }
463
-
464
501
/// How should the binding mode and expected type be adjusted?
465
502
///
466
503
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
467
504
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
505
match & pat. kind {
474
506
// Type checking these product-like types successfully always require
475
507
// that the expected type be of those types and not reference types.
@@ -526,64 +558,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
526
558
}
527
559
}
528
560
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
561
fn check_pat_expr_unadjusted ( & self , lt : & ' tcx hir:: PatExpr < ' tcx > ) -> Ty < ' tcx > {
588
562
let ty = match & lt. kind {
589
563
rustc_hir:: PatExprKind :: Lit { lit, negated } => {
0 commit comments