@@ -40,43 +40,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
40
40
& mut self ,
41
41
candidate : & mut Candidate < ' pat , ' tcx > ,
42
42
) -> bool {
43
- // repeatedly simplify match pairs until fixed point is reached
44
43
debug ! ( "{candidate:#?}" ) ;
45
-
46
- // existing_bindings and new_bindings exists to keep the semantics in order.
47
- // Reversing the binding order for bindings after `@` changes the binding order in places
48
- // it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`
44
+ // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the
45
+ // bindings in `pat` before `x`. E.g. (#69971):
46
+ //
47
+ // struct NonCopyStruct {
48
+ // copy_field: u32,
49
+ // }
50
+ //
51
+ // fn foo1(x: NonCopyStruct) {
52
+ // let y @ NonCopyStruct { copy_field: z } = x;
53
+ // // the above should turn into
54
+ // let z = x.copy_field;
55
+ // let y = x;
56
+ // }
49
57
//
50
- // To avoid this, the binding occurs in the following manner:
51
- // * the bindings for one iteration of the following loop occurs in order (i.e. left to
52
- // right)
53
- // * the bindings from the previous iteration of the loop is prepended to the bindings from
54
- // the current iteration (in the implementation this is done by mem::swap and extend)
55
- // * after all iterations, these new bindings are then appended to the bindings that were
56
- // preexisting (i.e. `candidate.binding` when the function was called).
58
+ // We can't just reverse the binding order, because we must preserve pattern-order
59
+ // otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first,
60
+ // and bindings at the same depth stay in source order.
61
+ //
62
+ // To do this, every time around the loop we prepend the newly found bindings to the
63
+ // bindings we already had.
57
64
//
58
65
// example:
59
66
// candidate.bindings = [1, 2, 3]
60
- // binding in iter 1: [4, 5]
61
- // binding in iter 2: [6, 7]
67
+ // bindings in iter 1: [4, 5]
68
+ // bindings in iter 2: [6, 7]
62
69
//
63
- // final binding : [1, 2, 3, 6, 7, 4, 5 ]
64
- let mut existing_bindings = mem:: take ( & mut candidate. bindings ) ;
65
- let mut new_bindings = Vec :: new ( ) ;
70
+ // final bindings : [6, 7, 4, 5, 1, 2, 3 ]
71
+ let mut accumulated_bindings = mem:: take ( & mut candidate. bindings ) ;
72
+ // Repeatedly simplify match pairs until fixed point is reached
66
73
loop {
67
- let match_pairs = mem:: take ( & mut candidate. match_pairs ) ;
68
-
69
- if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place } ] =
70
- & * match_pairs
71
- {
72
- existing_bindings. extend_from_slice ( & new_bindings) ;
73
- mem:: swap ( & mut candidate. bindings , & mut existing_bindings) ;
74
- candidate. subcandidates = self . create_or_subcandidates ( candidate, place, pats) ;
75
- return true ;
76
- }
77
-
78
74
let mut changed = false ;
79
- for match_pair in match_pairs {
75
+ for match_pair in mem :: take ( & mut candidate . match_pairs ) {
80
76
match self . simplify_match_pair ( match_pair, candidate) {
81
77
Ok ( ( ) ) => {
82
78
changed = true ;
@@ -86,36 +82,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
86
82
}
87
83
}
88
84
}
89
- // Avoid issue #69971: the binding order should be right to left if there are more
90
- // bindings after `@` to please the borrow checker
91
- // Ex
92
- // struct NonCopyStruct {
93
- // copy_field: u32,
94
- // }
95
- //
96
- // fn foo1(x: NonCopyStruct) {
97
- // let y @ NonCopyStruct { copy_field: z } = x;
98
- // // the above should turn into
99
- // let z = x.copy_field;
100
- // let y = x;
101
- // }
102
- candidate. bindings . extend_from_slice ( & new_bindings) ;
103
- mem:: swap ( & mut candidate. bindings , & mut new_bindings) ;
85
+
86
+ // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
87
+ candidate. bindings . extend_from_slice ( & accumulated_bindings) ;
88
+ mem:: swap ( & mut candidate. bindings , & mut accumulated_bindings) ;
104
89
candidate. bindings . clear ( ) ;
105
90
106
91
if !changed {
107
- existing_bindings. extend_from_slice ( & new_bindings) ;
108
- mem:: swap ( & mut candidate. bindings , & mut existing_bindings) ;
109
- // Move or-patterns to the end, because they can result in us
110
- // creating additional candidates, so we want to test them as
111
- // late as possible.
112
- candidate
113
- . match_pairs
114
- . sort_by_key ( |pair| matches ! ( pair. pattern. kind, PatKind :: Or { .. } ) ) ;
115
- debug ! ( simplified = ?candidate, "simplify_candidate" ) ;
116
- return false ; // if we were not able to simplify any, done.
92
+ // If we were not able to simplify anymore, done.
93
+ break ;
117
94
}
118
95
}
96
+
97
+ // Store computed bindings back in `candidate`.
98
+ mem:: swap ( & mut candidate. bindings , & mut accumulated_bindings) ;
99
+
100
+ let did_expand_or =
101
+ if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place } ] =
102
+ & * candidate. match_pairs
103
+ {
104
+ candidate. subcandidates = self . create_or_subcandidates ( candidate, place, pats) ;
105
+ candidate. match_pairs . clear ( ) ;
106
+ true
107
+ } else {
108
+ false
109
+ } ;
110
+
111
+ // Move or-patterns to the end, because they can result in us
112
+ // creating additional candidates, so we want to test them as
113
+ // late as possible.
114
+ candidate. match_pairs . sort_by_key ( |pair| matches ! ( pair. pattern. kind, PatKind :: Or { .. } ) ) ;
115
+ debug ! ( simplified = ?candidate, "simplify_candidate" ) ;
116
+
117
+ did_expand_or
119
118
}
120
119
121
120
/// Given `candidate` that has a single or-pattern for its match-pairs,
0 commit comments