@@ -25,11 +25,17 @@ pub enum DecisionTree<'db> {
25
25
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
26
26
pub struct Occurrence ( pub Vec < usize > ) ;
27
27
28
+ impl Default for Occurrence {
29
+ fn default ( ) -> Self {
30
+ Self :: new ( )
31
+ }
32
+ }
33
+
28
34
impl Occurrence {
29
35
pub fn new ( ) -> Self {
30
36
Self ( vec ! [ ] )
31
37
}
32
-
38
+
33
39
pub fn child ( & self , index : usize ) -> Self {
34
40
let mut path = self . 0 . clone ( ) ;
35
41
path. push ( index) ;
@@ -53,40 +59,51 @@ fn build_decision_tree_with_arms<'db>(
53
59
if matrix. nrows ( ) == 0 {
54
60
panic ! ( "Cannot build decision tree from empty matrix" ) ;
55
61
}
56
-
62
+
57
63
if matrix. ncols ( ) == 0 || is_all_wildcards ( matrix, 0 ) {
58
64
return DecisionTree :: Leaf {
59
65
arm_index : arm_indices[ 0 ] ,
60
66
bindings : vec ! [ ] ,
61
67
} ;
62
68
}
63
-
69
+
64
70
// For now, always select column 0
65
71
let occurrence = Occurrence :: new ( ) ;
66
72
let ty = matrix. first_column_ty ( ) ;
67
73
let sigma_set = matrix. sigma_set ( ) ;
68
-
74
+
69
75
let mut branches = vec ! [ ] ;
70
76
for ctor in sigma_set. into_iter ( ) {
71
- let ( specialized_matrix, specialized_arms) = specialize_matrix_with_arms ( db, matrix, & arm_indices, ctor, true ) ;
77
+ let ( specialized_matrix, specialized_arms) =
78
+ specialize_matrix_with_arms ( db, matrix, & arm_indices, ctor, true ) ;
72
79
if specialized_matrix. nrows ( ) > 0 {
73
80
let subtree = build_decision_tree_with_arms ( db, & specialized_matrix, specialized_arms) ;
74
81
branches. push ( ( ctor, subtree) ) ;
75
82
}
76
83
}
77
-
84
+
78
85
let sigma_set = matrix. sigma_set ( ) ; // Recreate since we consumed it
79
86
let default = if !sigma_set. is_complete ( db, ty) {
80
- let ( specialized_matrix, specialized_arms) = specialize_matrix_with_arms ( db, matrix, & arm_indices, ConstructorKind :: Tuple ( ty) , false ) ;
87
+ let ( specialized_matrix, specialized_arms) = specialize_matrix_with_arms (
88
+ db,
89
+ matrix,
90
+ & arm_indices,
91
+ ConstructorKind :: Tuple ( ty) ,
92
+ false ,
93
+ ) ;
81
94
if specialized_matrix. nrows ( ) > 0 {
82
- Some ( Box :: new ( build_decision_tree_with_arms ( db, & specialized_matrix, specialized_arms) ) )
95
+ Some ( Box :: new ( build_decision_tree_with_arms (
96
+ db,
97
+ & specialized_matrix,
98
+ specialized_arms,
99
+ ) ) )
83
100
} else {
84
101
None
85
102
}
86
103
} else {
87
104
None
88
105
} ;
89
-
106
+
90
107
DecisionTree :: Switch {
91
108
occurrence,
92
109
branches,
@@ -103,29 +120,29 @@ fn specialize_matrix_with_arms<'db>(
103
120
) -> ( PatternMatrix < ' db > , Vec < usize > ) {
104
121
let mut new_rows = Vec :: new ( ) ;
105
122
let mut new_arms = Vec :: new ( ) ;
106
-
123
+
107
124
for ( row_idx, row) in matrix. rows . iter ( ) . enumerate ( ) {
108
125
let specialized_rows = if is_constructor {
109
126
row. phi_specialize ( db, ctor)
110
127
} else {
111
128
row. d_specialize ( db)
112
129
} ;
113
-
130
+
114
131
for specialized_row in specialized_rows {
115
132
new_rows. push ( specialized_row) ;
116
133
new_arms. push ( arm_indices[ row_idx] ) ;
117
134
}
118
135
}
119
-
136
+
120
137
( PatternMatrix :: new ( new_rows) , new_arms)
121
138
}
122
139
123
140
/// Check if the first row is all wildcards
124
- fn is_all_wildcards < ' db > ( matrix : & PatternMatrix < ' db > , row : usize ) -> bool {
141
+ fn is_all_wildcards ( matrix : & PatternMatrix < ' _ > , row : usize ) -> bool {
125
142
if row >= matrix. nrows ( ) {
126
143
return false ;
127
144
}
128
-
145
+
129
146
matrix. rows [ row] . inner . iter ( ) . all ( |pat| pat. is_wildcard ( ) )
130
147
}
131
148
@@ -137,10 +154,10 @@ mod tests {
137
154
fn test_occurrence_creation ( ) {
138
155
let occ = Occurrence :: new ( ) ;
139
156
assert_eq ! ( occ. 0 , vec![ ] ) ;
140
-
157
+
141
158
let child = occ. child ( 0 ) ;
142
159
assert_eq ! ( child. 0 , vec![ 0 ] ) ;
143
-
160
+
144
161
let grandchild = child. child ( 1 ) ;
145
162
assert_eq ! ( grandchild. 0 , vec![ 0 , 1 ] ) ;
146
163
}
@@ -151,7 +168,7 @@ mod tests {
151
168
let tuple_first = root. child ( 0 ) ;
152
169
let tuple_second = root. child ( 1 ) ;
153
170
let nested = tuple_first. child ( 0 ) . child ( 1 ) ;
154
-
171
+
155
172
assert_eq ! ( root. 0 , vec![ ] ) ;
156
173
assert_eq ! ( tuple_first. 0 , vec![ 0 ] ) ;
157
174
assert_eq ! ( tuple_second. 0 , vec![ 1 ] ) ;
@@ -164,9 +181,12 @@ mod tests {
164
181
arm_index : 0 ,
165
182
bindings : vec ! [ ( "x" . to_string( ) , Occurrence :: new( ) ) ] ,
166
183
} ;
167
-
184
+
168
185
match leaf {
169
- DecisionTree :: Leaf { arm_index, bindings } => {
186
+ DecisionTree :: Leaf {
187
+ arm_index,
188
+ bindings,
189
+ } => {
170
190
assert_eq ! ( arm_index, 0 ) ;
171
191
assert_eq ! ( bindings. len( ) , 1 ) ;
172
192
assert_eq ! ( bindings[ 0 ] . 0 , "x" ) ;
@@ -182,15 +202,19 @@ mod tests {
182
202
arm_index : 0 ,
183
203
bindings : vec ! [ ] ,
184
204
} ;
185
-
205
+
186
206
let switch = DecisionTree :: Switch {
187
207
occurrence : Occurrence :: new ( ) ,
188
208
branches : vec ! [ ] ,
189
209
default : Some ( Box :: new ( leaf) ) ,
190
210
} ;
191
-
211
+
192
212
match switch {
193
- DecisionTree :: Switch { occurrence, branches, default } => {
213
+ DecisionTree :: Switch {
214
+ occurrence,
215
+ branches,
216
+ default,
217
+ } => {
194
218
assert_eq ! ( occurrence, Occurrence :: new( ) ) ;
195
219
assert_eq ! ( branches. len( ) , 0 ) ;
196
220
assert ! ( default . is_some( ) ) ;
@@ -201,27 +225,26 @@ mod tests {
201
225
202
226
#[ test]
203
227
fn test_is_all_wildcards_helper ( ) {
204
- use crate :: ty:: pattern_analysis:: { PatternMatrix , PatternRowVec , SimplifiedPattern , SimplifiedPatternKind } ;
205
- use crate :: ty:: ty_def:: TyId ;
206
-
228
+ use crate :: ty:: pattern_analysis:: PatternMatrix ;
229
+
207
230
// Test with empty matrix
208
231
let empty_matrix = PatternMatrix :: new ( vec ! [ ] ) ;
209
232
assert ! ( !is_all_wildcards( & empty_matrix, 0 ) ) ;
210
233
assert ! ( !is_all_wildcards( & empty_matrix, 1 ) ) ;
211
-
234
+
212
235
// Test with wildcard pattern - we can't easily create a TyId without a db,
213
236
// so this test shows the intended structure
214
237
}
215
238
216
239
// Helper to create a mock database for testing
217
240
// For now, we'll create minimal tests that don't require full pattern matrices
218
-
241
+
219
242
#[ test]
220
243
fn test_decision_tree_api_coverage ( ) {
221
244
// Test that our decision tree structures work as expected
222
245
let occurrence = Occurrence :: new ( ) ;
223
246
let child_occurrence = occurrence. child ( 0 ) ;
224
-
247
+
225
248
// Test leaf creation with bindings
226
249
let leaf = DecisionTree :: Leaf {
227
250
arm_index : 1 ,
@@ -230,27 +253,36 @@ mod tests {
230
253
( "y" . to_string( ) , child_occurrence) ,
231
254
] ,
232
255
} ;
233
-
234
- if let DecisionTree :: Leaf { arm_index, bindings } = leaf {
256
+
257
+ if let DecisionTree :: Leaf {
258
+ arm_index,
259
+ bindings,
260
+ } = leaf
261
+ {
235
262
assert_eq ! ( arm_index, 1 ) ;
236
263
assert_eq ! ( bindings. len( ) , 2 ) ;
237
264
} else {
238
265
panic ! ( "Expected leaf" ) ;
239
266
}
240
-
267
+
241
268
// Test switch creation with multiple branches
242
269
let branch_leaf = DecisionTree :: Leaf {
243
270
arm_index : 0 ,
244
271
bindings : vec ! [ ] ,
245
272
} ;
246
-
273
+
247
274
let switch = DecisionTree :: Switch {
248
275
occurrence : Occurrence :: new ( ) ,
249
276
branches : vec ! [ ] , // We can't easily create ConstructorKind without full setup
250
277
default : Some ( Box :: new ( branch_leaf) ) ,
251
278
} ;
252
-
253
- if let DecisionTree :: Switch { occurrence, branches, default } = switch {
279
+
280
+ if let DecisionTree :: Switch {
281
+ occurrence,
282
+ branches,
283
+ default,
284
+ } = switch
285
+ {
254
286
assert_eq ! ( occurrence, Occurrence :: new( ) ) ;
255
287
assert_eq ! ( branches. len( ) , 0 ) ;
256
288
assert ! ( default . is_some( ) ) ;
@@ -264,16 +296,16 @@ mod tests {
264
296
// Test building complex occurrence paths
265
297
let root = Occurrence :: new ( ) ;
266
298
assert_eq ! ( root. 0 , vec![ ] ) ;
267
-
299
+
268
300
// Simulate accessing tuple.0.field.1
269
301
let tuple_field = root. child ( 0 ) ;
270
302
let nested_field = tuple_field. child ( 2 ) ;
271
303
let final_access = nested_field. child ( 1 ) ;
272
-
304
+
273
305
assert_eq ! ( tuple_field. 0 , vec![ 0 ] ) ;
274
306
assert_eq ! ( nested_field. 0 , vec![ 0 , 2 ] ) ;
275
307
assert_eq ! ( final_access. 0 , vec![ 0 , 2 , 1 ] ) ;
276
-
308
+
277
309
// Test that different paths are independent
278
310
let other_path = root. child ( 1 ) . child ( 0 ) ;
279
311
assert_eq ! ( other_path. 0 , vec![ 1 , 0 ] ) ;
@@ -287,23 +319,35 @@ mod tests {
287
319
arm_index : 2 ,
288
320
bindings : vec ! [ ( "inner" . to_string( ) , Occurrence :: new( ) . child( 1 ) ) ] ,
289
321
} ;
290
-
322
+
291
323
let outer_switch = DecisionTree :: Switch {
292
324
occurrence : Occurrence :: new ( ) ,
293
- branches : vec ! [ ] ,
325
+ branches : vec ! [ ] ,
294
326
default : Some ( Box :: new ( inner_leaf) ) ,
295
327
} ;
296
-
328
+
297
329
let root_switch = DecisionTree :: Switch {
298
330
occurrence : Occurrence :: new ( ) ,
299
331
branches : vec ! [ ] ,
300
332
default : Some ( Box :: new ( outer_switch) ) ,
301
333
} ;
302
-
334
+
303
335
// Verify nested structure
304
- if let DecisionTree :: Switch { default : Some ( inner) , .. } = root_switch {
305
- if let DecisionTree :: Switch { default : Some ( leaf) , .. } = * inner {
306
- if let DecisionTree :: Leaf { arm_index, bindings } = * leaf {
336
+ if let DecisionTree :: Switch {
337
+ default : Some ( inner) ,
338
+ ..
339
+ } = root_switch
340
+ {
341
+ if let DecisionTree :: Switch {
342
+ default : Some ( leaf) ,
343
+ ..
344
+ } = * inner
345
+ {
346
+ if let DecisionTree :: Leaf {
347
+ arm_index,
348
+ bindings,
349
+ } = * leaf
350
+ {
307
351
assert_eq ! ( arm_index, 2 ) ;
308
352
assert_eq ! ( bindings. len( ) , 1 ) ;
309
353
} else {
@@ -316,4 +360,4 @@ mod tests {
316
360
panic ! ( "Expected root switch" ) ;
317
361
}
318
362
}
319
- }
363
+ }
0 commit comments