@@ -66,9 +66,11 @@ const INLINE_CONSTRAINT_BLOCKS: usize = 2;
66
66
const INLINE_VISIBLE_DEFINITIONS_PER_SYMBOL : usize = 4 ;
67
67
68
68
/// One [`BitSet`] of applicable [`ScopedConstraintId`] per visible definition.
69
- type Constraints =
70
- SmallVec < [ BitSet < INLINE_CONSTRAINT_BLOCKS > ; INLINE_VISIBLE_DEFINITIONS_PER_SYMBOL ] > ;
69
+ type InlineConstraintArray =
70
+ [ BitSet < INLINE_CONSTRAINT_BLOCKS > ; INLINE_VISIBLE_DEFINITIONS_PER_SYMBOL ] ;
71
+ type Constraints = SmallVec < InlineConstraintArray > ;
71
72
type ConstraintsIterator < ' a > = std:: slice:: Iter < ' a , BitSet < INLINE_CONSTRAINT_BLOCKS > > ;
73
+ type ConstraintsIntoIterator = smallvec:: IntoIter < InlineConstraintArray > ;
72
74
73
75
/// Visible definitions and narrowing constraints for a single symbol at some point in control flow.
74
76
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -126,17 +128,18 @@ impl SymbolState {
126
128
}
127
129
}
128
130
129
- /// Merge two [`SymbolState`] and return the result .
130
- pub ( super ) fn merge ( a : & SymbolState , b : & SymbolState ) -> SymbolState {
131
- let mut merged = Self {
131
+ /// Merge another [`SymbolState`] into this one .
132
+ pub ( super ) fn merge ( & mut self , b : SymbolState ) {
133
+ let mut a = Self {
132
134
visible_definitions : Definitions :: default ( ) ,
133
135
constraints : Constraints :: default ( ) ,
134
- may_be_unbound : a . may_be_unbound || b. may_be_unbound ,
136
+ may_be_unbound : self . may_be_unbound || b. may_be_unbound ,
135
137
} ;
138
+ std:: mem:: swap ( & mut a, self ) ;
136
139
let mut a_defs_iter = a. visible_definitions . iter ( ) ;
137
140
let mut b_defs_iter = b. visible_definitions . iter ( ) ;
138
- let mut a_constraints_iter = a. constraints . iter ( ) ;
139
- let mut b_constraints_iter = b. constraints . iter ( ) ;
141
+ let mut a_constraints_iter = a. constraints . into_iter ( ) ;
142
+ let mut b_constraints_iter = b. constraints . into_iter ( ) ;
140
143
141
144
let mut opt_a_def: Option < u32 > = a_defs_iter. next ( ) ;
142
145
let mut opt_b_def: Option < u32 > = b_defs_iter. next ( ) ;
@@ -147,8 +150,8 @@ impl SymbolState {
147
150
// of the constraints from the two paths; a constraint that applies from only one possible
148
151
// path is irrelevant.
149
152
150
- // Helper to push `def`, with constraints in `constraints_iter`, onto merged `.
151
- let push = |def, constraints_iter : & mut ConstraintsIterator , merged : & mut Self | {
153
+ // Helper to push `def`, with constraints in `constraints_iter`, onto `self `.
154
+ let push = |def, constraints_iter : & mut ConstraintsIntoIterator , merged : & mut Self | {
152
155
merged. visible_definitions . insert ( def) ;
153
156
// SAFETY: we only ever create SymbolState with either no definitions and no constraint
154
157
// bitsets (`::unbound`) or one definition and one constraint bitset (`::with`), and
@@ -158,59 +161,57 @@ impl SymbolState {
158
161
let constraints = constraints_iter
159
162
. next ( )
160
163
. expect ( "definitions and constraints length mismatch" ) ;
161
- merged. constraints . push ( constraints. clone ( ) ) ;
164
+ merged. constraints . push ( constraints) ;
162
165
} ;
163
166
164
167
loop {
165
168
match ( opt_a_def, opt_b_def) {
166
169
( Some ( a_def) , Some ( b_def) ) => match a_def. cmp ( & b_def) {
167
170
std:: cmp:: Ordering :: Less => {
168
- // Next definition ID is only in `a`, push it to `merged ` and advance `a`.
169
- push ( a_def, & mut a_constraints_iter, & mut merged ) ;
171
+ // Next definition ID is only in `a`, push it to `self ` and advance `a`.
172
+ push ( a_def, & mut a_constraints_iter, self ) ;
170
173
opt_a_def = a_defs_iter. next ( ) ;
171
174
}
172
175
std:: cmp:: Ordering :: Greater => {
173
- // Next definition ID is only in `b`, push it to `merged ` and advance `b`.
174
- push ( b_def, & mut b_constraints_iter, & mut merged ) ;
176
+ // Next definition ID is only in `b`, push it to `self ` and advance `b`.
177
+ push ( b_def, & mut b_constraints_iter, self ) ;
175
178
opt_b_def = b_defs_iter. next ( ) ;
176
179
}
177
180
std:: cmp:: Ordering :: Equal => {
178
- // Next definition is in both; push to `merged ` and intersect constraints.
179
- push ( a_def, & mut a_constraints_iter , & mut merged ) ;
181
+ // Next definition is in both; push to `self ` and intersect constraints.
182
+ push ( a_def, & mut b_constraints_iter , self ) ;
180
183
// SAFETY: we only ever create SymbolState with either no definitions and
181
184
// no constraint bitsets (`::unbound`) or one definition and one constraint
182
185
// bitset (`::with`), and `::merge` always pushes one definition and one
183
186
// constraint bitset together (just below), so the number of definitions
184
187
// and the number of constraint bitsets can never get out of sync.
185
- let b_constraints = b_constraints_iter
188
+ let a_constraints = a_constraints_iter
186
189
. next ( )
187
190
. expect ( "definitions and constraints length mismatch" ) ;
188
191
// If the same definition is visible through both paths, any constraint
189
192
// that applies on only one path is irrelevant to the resulting type from
190
193
// unioning the two paths, so we intersect the constraints.
191
- merged
192
- . constraints
194
+ self . constraints
193
195
. last_mut ( )
194
196
. unwrap ( )
195
- . intersect ( b_constraints ) ;
197
+ . intersect ( & a_constraints ) ;
196
198
opt_a_def = a_defs_iter. next ( ) ;
197
199
opt_b_def = b_defs_iter. next ( ) ;
198
200
}
199
201
} ,
200
202
( Some ( a_def) , None ) => {
201
203
// We've exhausted `b`, just push the def from `a` and move on to the next.
202
- push ( a_def, & mut a_constraints_iter, & mut merged ) ;
204
+ push ( a_def, & mut a_constraints_iter, self ) ;
203
205
opt_a_def = a_defs_iter. next ( ) ;
204
206
}
205
207
( None , Some ( b_def) ) => {
206
208
// We've exhausted `a`, just push the def from `b` and move on to the next.
207
- push ( b_def, & mut b_constraints_iter, & mut merged ) ;
209
+ push ( b_def, & mut b_constraints_iter, self ) ;
208
210
opt_b_def = b_defs_iter. next ( ) ;
209
211
}
210
212
( None , None ) => break ,
211
213
}
212
214
}
213
- merged
214
215
}
215
216
216
217
/// Get iterator over visible definitions with constraints.
@@ -340,7 +341,8 @@ mod tests {
340
341
let mut cd0b = SymbolState :: with ( ScopedDefinitionId :: from_u32 ( 0 ) ) ;
341
342
cd0b. add_constraint ( ScopedConstraintId :: from_u32 ( 0 ) ) ;
342
343
343
- let cd0 = SymbolState :: merge ( & cd0a, & cd0b) ;
344
+ cd0a. merge ( cd0b) ;
345
+ let mut cd0 = cd0a;
344
346
cd0. assert ( false , & [ "0<0>" ] ) ;
345
347
346
348
// merging the same definition with differing constraints drops all constraints
@@ -350,7 +352,8 @@ mod tests {
350
352
let mut cd1b = SymbolState :: with ( ScopedDefinitionId :: from_u32 ( 1 ) ) ;
351
353
cd1b. add_constraint ( ScopedConstraintId :: from_u32 ( 2 ) ) ;
352
354
353
- let cd1 = SymbolState :: merge ( & cd1a, & cd1b) ;
355
+ cd1a. merge ( cd1b) ;
356
+ let cd1 = cd1a;
354
357
cd1. assert ( false , & [ "1<>" ] ) ;
355
358
356
359
// merging a constrained definition with unbound keeps both
@@ -359,11 +362,13 @@ mod tests {
359
362
360
363
let cd2b = SymbolState :: unbound ( ) ;
361
364
362
- let cd2 = SymbolState :: merge ( & cd2a, & cd2b) ;
365
+ cd2a. merge ( cd2b) ;
366
+ let cd2 = cd2a;
363
367
cd2. assert ( true , & [ "2<3>" ] ) ;
364
368
365
369
// merging different definitions keeps them each with their existing constraints
366
- let cd = SymbolState :: merge ( & cd0, & cd2) ;
370
+ cd0. merge ( cd2) ;
371
+ let cd = cd0;
367
372
cd. assert ( true , & [ "0<0>" , "2<3>" ] ) ;
368
373
}
369
374
}
0 commit comments