@@ -2,7 +2,10 @@ use crate::borrow_check::ArtificialField;
2
2
use crate :: borrow_check:: Overlap ;
3
3
use crate :: borrow_check:: { Deep , Shallow , AccessDepth } ;
4
4
use rustc:: hir;
5
- use rustc:: mir:: { BorrowKind , Mir , Place , PlaceBase , Projection , ProjectionElem , StaticKind } ;
5
+ use rustc:: mir:: {
6
+ BorrowKind , Mir , Place , PlaceBase , PlaceProjection , ProjectionElem , PlaceProjectionsIter ,
7
+ StaticKind
8
+ } ;
6
9
use rustc:: ty:: { self , TyCtxt } ;
7
10
use std:: cmp:: max;
8
11
@@ -65,14 +68,14 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
65
68
}
66
69
}
67
70
68
- unroll_place ( borrow_place, None , |borrow_components | {
69
- unroll_place ( access_place, None , |access_components | {
71
+ borrow_place. iterate ( |borrow_base , borrow_projections | {
72
+ access_place. iterate ( |access_base , access_projections | {
70
73
place_components_conflict (
71
74
tcx,
72
75
mir,
73
- borrow_components ,
76
+ ( borrow_base , borrow_projections ) ,
74
77
borrow_kind,
75
- access_components ,
78
+ ( access_base , access_projections ) ,
76
79
access,
77
80
bias,
78
81
)
@@ -83,9 +86,9 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
83
86
fn place_components_conflict < ' gcx , ' tcx > (
84
87
tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
85
88
mir : & Mir < ' tcx > ,
86
- mut borrow_components : PlaceComponentsIter < ' _ , ' tcx > ,
89
+ borrow_projections : ( & PlaceBase < ' tcx > , PlaceProjectionsIter < ' _ , ' tcx > ) ,
87
90
borrow_kind : BorrowKind ,
88
- mut access_components : PlaceComponentsIter < ' _ , ' tcx > ,
91
+ access_projections : ( & PlaceBase < ' tcx > , PlaceProjectionsIter < ' _ , ' tcx > ) ,
89
92
access : AccessDepth ,
90
93
bias : PlaceConflictBias ,
91
94
) -> bool {
@@ -130,12 +133,34 @@ fn place_components_conflict<'gcx, 'tcx>(
130
133
// - If we didn't run out of access to match, our borrow and access are comparable
131
134
// and either equal or disjoint.
132
135
// - If we did run out of access, the borrow can access a part of it.
136
+
137
+ let borrow_base = borrow_projections. 0 ;
138
+ let access_base = access_projections. 0 ;
139
+
140
+ match place_base_conflict ( tcx, borrow_base, access_base) {
141
+ Overlap :: Arbitrary => {
142
+ bug ! ( "Two base can't return Arbitrary" ) ;
143
+ }
144
+ Overlap :: EqualOrDisjoint => {
145
+ // This is the recursive case - proceed to the next element.
146
+ }
147
+ Overlap :: Disjoint => {
148
+ // We have proven the borrow disjoint - further
149
+ // projections will remain disjoint.
150
+ debug ! ( "borrow_conflicts_with_place: disjoint" ) ;
151
+ return false ;
152
+ }
153
+ }
154
+
155
+ let mut borrow_projections = borrow_projections. 1 ;
156
+ let mut access_projections = access_projections. 1 ;
157
+
133
158
loop {
134
159
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
135
- if let Some ( borrow_c) = borrow_components . next ( ) {
160
+ if let Some ( borrow_c) = borrow_projections . next ( ) {
136
161
debug ! ( "borrow_conflicts_with_place: borrow_c = {:?}" , borrow_c) ;
137
162
138
- if let Some ( access_c) = access_components . next ( ) {
163
+ if let Some ( access_c) = access_projections . next ( ) {
139
164
debug ! ( "borrow_conflicts_with_place: access_c = {:?}" , access_c) ;
140
165
141
166
// Borrow and access path both have more components.
@@ -150,7 +175,7 @@ fn place_components_conflict<'gcx, 'tcx>(
150
175
// check whether the components being borrowed vs
151
176
// accessed are disjoint (as in the second example,
152
177
// but not the first).
153
- match place_element_conflict ( tcx, mir, borrow_c, access_c, bias) {
178
+ match place_projection_conflict ( tcx, mir, borrow_c, access_c, bias) {
154
179
Overlap :: Arbitrary => {
155
180
// We have encountered different fields of potentially
156
181
// the same union - the borrow now partially overlaps.
@@ -187,10 +212,8 @@ fn place_components_conflict<'gcx, 'tcx>(
187
212
// our place. This is a conflict if that is a part our
188
213
// access cares about.
189
214
190
- let ( base, elem) = match borrow_c {
191
- Place :: Projection ( box Projection { base, elem } ) => ( base, elem) ,
192
- _ => bug ! ( "place has no base?" ) ,
193
- } ;
215
+ let base = & borrow_c. base ;
216
+ let elem = & borrow_c. elem ;
194
217
let base_ty = base. ty ( mir, tcx) . ty ;
195
218
196
219
match ( elem, & base_ty. sty , access) {
@@ -261,7 +284,7 @@ fn place_components_conflict<'gcx, 'tcx>(
261
284
// If the second example, where we did, then we still know
262
285
// that the borrow can access a *part* of our place that
263
286
// our access cares about, so we still have a conflict.
264
- if borrow_kind == BorrowKind :: Shallow && access_components . next ( ) . is_some ( ) {
287
+ if borrow_kind == BorrowKind :: Shallow && access_projections . next ( ) . is_some ( ) {
265
288
debug ! ( "borrow_conflicts_with_place: shallow borrow" ) ;
266
289
return false ;
267
290
} else {
@@ -272,94 +295,16 @@ fn place_components_conflict<'gcx, 'tcx>(
272
295
}
273
296
}
274
297
275
- /// A linked list of places running up the stack; begins with the
276
- /// innermost place and extends to projections (e.g., `a.b` would have
277
- /// the place `a` with a "next" pointer to `a.b`). Created by
278
- /// `unroll_place`.
279
- ///
280
- /// N.B., this particular impl strategy is not the most obvious. It was
281
- /// chosen because it makes a measurable difference to NLL
282
- /// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
283
- struct PlaceComponents < ' p , ' tcx : ' p > {
284
- component : & ' p Place < ' tcx > ,
285
- next : Option < & ' p PlaceComponents < ' p , ' tcx > > ,
286
- }
287
-
288
- impl < ' p , ' tcx > PlaceComponents < ' p , ' tcx > {
289
- /// Converts a list of `Place` components into an iterator; this
290
- /// iterator yields up a never-ending stream of `Option<&Place>`.
291
- /// These begin with the "innermost" place and then with each
292
- /// projection therefrom. So given a place like `a.b.c` it would
293
- /// yield up:
294
- ///
295
- /// ```notrust
296
- /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
297
- /// ```
298
- fn iter ( & self ) -> PlaceComponentsIter < ' _ , ' tcx > {
299
- PlaceComponentsIter { value : Some ( self ) }
300
- }
301
- }
302
-
303
- /// Iterator over components; see `PlaceComponents::iter` for more
304
- /// information.
305
- ///
306
- /// N.B., this is not a *true* Rust iterator -- the code above just
307
- /// manually invokes `next`. This is because we (sometimes) want to
308
- /// keep executing even after `None` has been returned.
309
- struct PlaceComponentsIter < ' p , ' tcx : ' p > {
310
- value : Option < & ' p PlaceComponents < ' p , ' tcx > > ,
311
- }
312
-
313
- impl < ' p , ' tcx > PlaceComponentsIter < ' p , ' tcx > {
314
- fn next ( & mut self ) -> Option < & ' p Place < ' tcx > > {
315
- if let Some ( & PlaceComponents { component, next } ) = self . value {
316
- self . value = next;
317
- Some ( component)
318
- } else {
319
- None
320
- }
321
- }
322
- }
323
-
324
- /// Recursively "unroll" a place into a `PlaceComponents` list,
325
- /// invoking `op` with a `PlaceComponentsIter`.
326
- fn unroll_place < ' tcx , R > (
327
- place : & Place < ' tcx > ,
328
- next : Option < & PlaceComponents < ' _ , ' tcx > > ,
329
- op : impl FnOnce ( PlaceComponentsIter < ' _ , ' tcx > ) -> R ,
330
- ) -> R {
331
- match place {
332
- Place :: Projection ( interior) => unroll_place (
333
- & interior. base ,
334
- Some ( & PlaceComponents {
335
- component : place,
336
- next,
337
- } ) ,
338
- op,
339
- ) ,
340
-
341
- Place :: Base ( PlaceBase :: Local ( _) ) | Place :: Base ( PlaceBase :: Static ( _) ) => {
342
- let list = PlaceComponents {
343
- component : place,
344
- next,
345
- } ;
346
- op ( list. iter ( ) )
347
- }
348
- }
349
- }
350
-
351
298
// Given that the bases of `elem1` and `elem2` are always either equal
352
299
// or disjoint (and have the same type!), return the overlap situation
353
300
// between `elem1` and `elem2`.
354
- fn place_element_conflict < ' a , ' gcx : ' tcx , ' tcx > (
301
+ fn place_base_conflict < ' a , ' gcx : ' tcx , ' tcx > (
355
302
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
356
- mir : & Mir < ' tcx > ,
357
- elem1 : & Place < ' tcx > ,
358
- elem2 : & Place < ' tcx > ,
359
- bias : PlaceConflictBias ,
303
+ elem1 : & PlaceBase < ' tcx > ,
304
+ elem2 : & PlaceBase < ' tcx > ,
360
305
) -> Overlap {
361
306
match ( elem1, elem2) {
362
- ( Place :: Base ( PlaceBase :: Local ( l1) ) , Place :: Base ( PlaceBase :: Local ( l2) ) ) => {
307
+ ( PlaceBase :: Local ( l1) , PlaceBase :: Local ( l2) ) => {
363
308
if l1 == l2 {
364
309
// the same local - base case, equal
365
310
debug ! ( "place_element_conflict: DISJOINT-OR-EQ-LOCAL" ) ;
@@ -370,7 +315,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
370
315
Overlap :: Disjoint
371
316
}
372
317
}
373
- ( Place :: Base ( PlaceBase :: Static ( s1) ) , Place :: Base ( PlaceBase :: Static ( s2) ) ) => {
318
+ ( PlaceBase :: Static ( s1) , PlaceBase :: Static ( s2) ) => {
374
319
match ( & s1. kind , & s2. kind ) {
375
320
( StaticKind :: Static ( def_id_1) , StaticKind :: Static ( def_id_2) ) => {
376
321
if def_id_1 != def_id_2 {
@@ -409,174 +354,179 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
409
354
}
410
355
}
411
356
}
412
- ( Place :: Base ( PlaceBase :: Local ( _) ) , Place :: Base ( PlaceBase :: Static ( _) ) ) |
413
- ( Place :: Base ( PlaceBase :: Static ( _) ) , Place :: Base ( PlaceBase :: Local ( _) ) ) => {
357
+ ( PlaceBase :: Local ( _) , PlaceBase :: Static ( _) ) |
358
+ ( PlaceBase :: Static ( _) , PlaceBase :: Local ( _) ) => {
414
359
debug ! ( "place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED" ) ;
415
360
Overlap :: Disjoint
416
361
}
417
- ( Place :: Projection ( pi1) , Place :: Projection ( pi2) ) => {
418
- match ( & pi1. elem , & pi2. elem ) {
419
- ( ProjectionElem :: Deref , ProjectionElem :: Deref ) => {
420
- // derefs (e.g., `*x` vs. `*x`) - recur.
421
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-DEREF" ) ;
422
- Overlap :: EqualOrDisjoint
423
- }
424
- ( ProjectionElem :: Field ( f1, _) , ProjectionElem :: Field ( f2, _) ) => {
425
- if f1 == f2 {
426
- // same field (e.g., `a.y` vs. `a.y`) - recur.
427
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-FIELD" ) ;
428
- Overlap :: EqualOrDisjoint
429
- } else {
430
- let ty = pi1. base . ty ( mir, tcx) . ty ;
431
- match ty. sty {
432
- ty:: Adt ( def, _) if def. is_union ( ) => {
433
- // Different fields of a union, we are basically stuck.
434
- debug ! ( "place_element_conflict: STUCK-UNION" ) ;
435
- Overlap :: Arbitrary
436
- }
437
- _ => {
438
- // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
439
- debug ! ( "place_element_conflict: DISJOINT-FIELD" ) ;
440
- Overlap :: Disjoint
441
- }
442
- }
362
+ }
363
+ }
364
+
365
+ // Given that the bases of `elem1` and `elem2` are always either equal
366
+ // or disjoint (and have the same type!), return the overlap situation
367
+ // between `elem1` and `elem2`.
368
+ fn place_projection_conflict < ' a , ' gcx : ' tcx , ' tcx > (
369
+ tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
370
+ mir : & Mir < ' tcx > ,
371
+ pi1 : & PlaceProjection < ' tcx > ,
372
+ pi2 : & PlaceProjection < ' tcx > ,
373
+ bias : PlaceConflictBias ,
374
+ ) -> Overlap {
375
+ match ( & pi1. elem , & pi2. elem ) {
376
+ ( ProjectionElem :: Deref , ProjectionElem :: Deref ) => {
377
+ // derefs (e.g., `*x` vs. `*x`) - recur.
378
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-DEREF" ) ;
379
+ Overlap :: EqualOrDisjoint
380
+ }
381
+ ( ProjectionElem :: Field ( f1, _) , ProjectionElem :: Field ( f2, _) ) => {
382
+ if f1 == f2 {
383
+ // same field (e.g., `a.y` vs. `a.y`) - recur.
384
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-FIELD" ) ;
385
+ Overlap :: EqualOrDisjoint
386
+ } else {
387
+ let ty = pi1. base . ty ( mir, tcx) . ty ;
388
+ match ty. sty {
389
+ ty:: Adt ( def, _) if def. is_union ( ) => {
390
+ // Different fields of a union, we are basically stuck.
391
+ debug ! ( "place_element_conflict: STUCK-UNION" ) ;
392
+ Overlap :: Arbitrary
443
393
}
444
- }
445
- ( ProjectionElem :: Downcast ( _, v1) , ProjectionElem :: Downcast ( _, v2) ) => {
446
- // different variants are treated as having disjoint fields,
447
- // even if they occupy the same "space", because it's
448
- // impossible for 2 variants of the same enum to exist
449
- // (and therefore, to be borrowed) at the same time.
450
- //
451
- // Note that this is different from unions - we *do* allow
452
- // this code to compile:
453
- //
454
- // ```
455
- // fn foo(x: &mut Result<i32, i32>) {
456
- // let mut v = None;
457
- // if let Ok(ref mut a) = *x {
458
- // v = Some(a);
459
- // }
460
- // // here, you would *think* that the
461
- // // *entirety* of `x` would be borrowed,
462
- // // but in fact only the `Ok` variant is,
463
- // // so the `Err` variant is *entirely free*:
464
- // if let Err(ref mut a) = *x {
465
- // v = Some(a);
466
- // }
467
- // drop(v);
468
- // }
469
- // ```
470
- if v1 == v2 {
471
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-FIELD" ) ;
472
- Overlap :: EqualOrDisjoint
473
- } else {
394
+ _ => {
395
+ // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
474
396
debug ! ( "place_element_conflict: DISJOINT-FIELD" ) ;
475
397
Overlap :: Disjoint
476
398
}
477
399
}
478
- ( ProjectionElem :: Index ( ..) , ProjectionElem :: Index ( ..) )
479
- | ( ProjectionElem :: Index ( ..) , ProjectionElem :: ConstantIndex { .. } )
480
- | ( ProjectionElem :: Index ( ..) , ProjectionElem :: Subslice { .. } )
481
- | ( ProjectionElem :: ConstantIndex { .. } , ProjectionElem :: Index ( ..) )
482
- | ( ProjectionElem :: Subslice { .. } , ProjectionElem :: Index ( ..) ) => {
483
- // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
484
- // (if the indexes differ) or equal (if they are the same).
485
- match bias {
486
- PlaceConflictBias :: Overlap => {
487
- // If we are biased towards overlapping, then this is the recursive
488
- // case that gives "equal *or* disjoint" its meaning.
489
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX" ) ;
490
- Overlap :: EqualOrDisjoint
491
- }
492
- PlaceConflictBias :: NoOverlap => {
493
- // If we are biased towards no overlapping, then this is disjoint.
494
- debug ! ( "place_element_conflict: DISJOINT-ARRAY-INDEX" ) ;
495
- Overlap :: Disjoint
496
- }
497
- }
498
- }
499
- ( ProjectionElem :: ConstantIndex { offset : o1, min_length : _, from_end : false } ,
500
- ProjectionElem :: ConstantIndex { offset : o2, min_length : _, from_end : false } )
501
- | ( ProjectionElem :: ConstantIndex { offset : o1, min_length : _, from_end : true } ,
502
- ProjectionElem :: ConstantIndex {
503
- offset : o2, min_length : _, from_end : true } ) => {
504
- if o1 == o2 {
505
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX" ) ;
506
- Overlap :: EqualOrDisjoint
507
- } else {
508
- debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX" ) ;
509
- Overlap :: Disjoint
510
- }
511
- }
512
- ( ProjectionElem :: ConstantIndex {
513
- offset : offset_from_begin, min_length : min_length1, from_end : false } ,
514
- ProjectionElem :: ConstantIndex {
515
- offset : offset_from_end, min_length : min_length2, from_end : true } )
516
- | ( ProjectionElem :: ConstantIndex {
517
- offset : offset_from_end, min_length : min_length1, from_end : true } ,
518
- ProjectionElem :: ConstantIndex {
519
- offset : offset_from_begin, min_length : min_length2, from_end : false } ) => {
520
- // both patterns matched so it must be at least the greater of the two
521
- let min_length = max ( min_length1, min_length2) ;
522
- // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last
523
- // element (like -1 in Python) and `min_length` the first.
524
- // Therefore, `min_length - offset_from_end` gives the minimal possible
525
- // offset from the beginning
526
- if * offset_from_begin >= min_length - offset_from_end {
527
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE" ) ;
528
- Overlap :: EqualOrDisjoint
529
- } else {
530
- debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE" ) ;
531
- Overlap :: Disjoint
532
- }
533
- }
534
- ( ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : false } ,
535
- ProjectionElem :: Subslice { from, .. } )
536
- | ( ProjectionElem :: Subslice { from, .. } ,
537
- ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : false } ) => {
538
- if offset >= from {
539
- debug ! (
540
- "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE" ) ;
541
- Overlap :: EqualOrDisjoint
542
- } else {
543
- debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE" ) ;
544
- Overlap :: Disjoint
545
- }
546
- }
547
- ( ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : true } ,
548
- ProjectionElem :: Subslice { from : _, to } )
549
- | ( ProjectionElem :: Subslice { from : _, to } ,
550
- ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : true } ) => {
551
- if offset > to {
552
- debug ! ( "place_element_conflict: \
553
- DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE") ;
554
- Overlap :: EqualOrDisjoint
555
- } else {
556
- debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE" ) ;
557
- Overlap :: Disjoint
558
- }
400
+ }
401
+ }
402
+ ( ProjectionElem :: Downcast ( _, v1) , ProjectionElem :: Downcast ( _, v2) ) => {
403
+ // different variants are treated as having disjoint fields,
404
+ // even if they occupy the same "space", because it's
405
+ // impossible for 2 variants of the same enum to exist
406
+ // (and therefore, to be borrowed) at the same time.
407
+ //
408
+ // Note that this is different from unions - we *do* allow
409
+ // this code to compile:
410
+ //
411
+ // ```
412
+ // fn foo(x: &mut Result<i32, i32>) {
413
+ // let mut v = None;
414
+ // if let Ok(ref mut a) = *x {
415
+ // v = Some(a);
416
+ // }
417
+ // // here, you would *think* that the
418
+ // // *entirety* of `x` would be borrowed,
419
+ // // but in fact only the `Ok` variant is,
420
+ // // so the `Err` variant is *entirely free*:
421
+ // if let Err(ref mut a) = *x {
422
+ // v = Some(a);
423
+ // }
424
+ // drop(v);
425
+ // }
426
+ // ```
427
+ if v1 == v2 {
428
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-FIELD" ) ;
429
+ Overlap :: EqualOrDisjoint
430
+ } else {
431
+ debug ! ( "place_element_conflict: DISJOINT-FIELD" ) ;
432
+ Overlap :: Disjoint
433
+ }
434
+ }
435
+ ( ProjectionElem :: Index ( ..) , ProjectionElem :: Index ( ..) )
436
+ | ( ProjectionElem :: Index ( ..) , ProjectionElem :: ConstantIndex { .. } )
437
+ | ( ProjectionElem :: Index ( ..) , ProjectionElem :: Subslice { .. } )
438
+ | ( ProjectionElem :: ConstantIndex { .. } , ProjectionElem :: Index ( ..) )
439
+ | ( ProjectionElem :: Subslice { .. } , ProjectionElem :: Index ( ..) ) => {
440
+ // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
441
+ // (if the indexes differ) or equal (if they are the same).
442
+ match bias {
443
+ PlaceConflictBias :: Overlap => {
444
+ // If we are biased towards overlapping, then this is the recursive
445
+ // case that gives "equal *or* disjoint" its meaning.
446
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX" ) ;
447
+ Overlap :: EqualOrDisjoint
559
448
}
560
- ( ProjectionElem :: Subslice { .. } , ProjectionElem :: Subslice { .. } ) => {
561
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES" ) ;
562
- Overlap :: EqualOrDisjoint
449
+ PlaceConflictBias :: NoOverlap => {
450
+ // If we are biased towards no overlapping, then this is disjoint.
451
+ debug ! ( "place_element_conflict: DISJOINT-ARRAY-INDEX" ) ;
452
+ Overlap :: Disjoint
563
453
}
564
- ( ProjectionElem :: Deref , _)
565
- | ( ProjectionElem :: Field ( ..) , _)
566
- | ( ProjectionElem :: Index ( ..) , _)
567
- | ( ProjectionElem :: ConstantIndex { .. } , _)
568
- | ( ProjectionElem :: Subslice { .. } , _)
569
- | ( ProjectionElem :: Downcast ( ..) , _) => bug ! (
570
- "mismatched projections in place_element_conflict: {:?} and {:?}" ,
571
- elem1,
572
- elem2
573
- ) ,
574
454
}
575
455
}
576
- ( Place :: Projection ( _) , _) | ( _, Place :: Projection ( _) ) => bug ! (
577
- "unexpected elements in place_element_conflict: {:?} and {:?}" ,
578
- elem1,
579
- elem2
456
+ ( ProjectionElem :: ConstantIndex { offset : o1, min_length : _, from_end : false } ,
457
+ ProjectionElem :: ConstantIndex { offset : o2, min_length : _, from_end : false } )
458
+ | ( ProjectionElem :: ConstantIndex { offset : o1, min_length : _, from_end : true } ,
459
+ ProjectionElem :: ConstantIndex {
460
+ offset : o2, min_length : _, from_end : true } ) => {
461
+ if o1 == o2 {
462
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX" ) ;
463
+ Overlap :: EqualOrDisjoint
464
+ } else {
465
+ debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX" ) ;
466
+ Overlap :: Disjoint
467
+ }
468
+ }
469
+ ( ProjectionElem :: ConstantIndex {
470
+ offset : offset_from_begin, min_length : min_length1, from_end : false } ,
471
+ ProjectionElem :: ConstantIndex {
472
+ offset : offset_from_end, min_length : min_length2, from_end : true } )
473
+ | ( ProjectionElem :: ConstantIndex {
474
+ offset : offset_from_end, min_length : min_length1, from_end : true } ,
475
+ ProjectionElem :: ConstantIndex {
476
+ offset : offset_from_begin, min_length : min_length2, from_end : false } ) => {
477
+ // both patterns matched so it must be at least the greater of the two
478
+ let min_length = max ( min_length1, min_length2) ;
479
+ // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last
480
+ // element (like -1 in Python) and `min_length` the first.
481
+ // Therefore, `min_length - offset_from_end` gives the minimal possible
482
+ // offset from the beginning
483
+ if * offset_from_begin >= min_length - offset_from_end {
484
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE" ) ;
485
+ Overlap :: EqualOrDisjoint
486
+ } else {
487
+ debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE" ) ;
488
+ Overlap :: Disjoint
489
+ }
490
+ }
491
+ ( ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : false } ,
492
+ ProjectionElem :: Subslice { from, .. } )
493
+ | ( ProjectionElem :: Subslice { from, .. } ,
494
+ ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : false } ) => {
495
+ if offset >= from {
496
+ debug ! (
497
+ "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE" ) ;
498
+ Overlap :: EqualOrDisjoint
499
+ } else {
500
+ debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE" ) ;
501
+ Overlap :: Disjoint
502
+ }
503
+ }
504
+ ( ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : true } ,
505
+ ProjectionElem :: Subslice { from : _, to } )
506
+ | ( ProjectionElem :: Subslice { from : _, to } ,
507
+ ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : true } ) => {
508
+ if offset > to {
509
+ debug ! ( "place_element_conflict: \
510
+ DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE") ;
511
+ Overlap :: EqualOrDisjoint
512
+ } else {
513
+ debug ! ( "place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE" ) ;
514
+ Overlap :: Disjoint
515
+ }
516
+ }
517
+ ( ProjectionElem :: Subslice { .. } , ProjectionElem :: Subslice { .. } ) => {
518
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES" ) ;
519
+ Overlap :: EqualOrDisjoint
520
+ }
521
+ ( ProjectionElem :: Deref , _)
522
+ | ( ProjectionElem :: Field ( ..) , _)
523
+ | ( ProjectionElem :: Index ( ..) , _)
524
+ | ( ProjectionElem :: ConstantIndex { .. } , _)
525
+ | ( ProjectionElem :: Subslice { .. } , _)
526
+ | ( ProjectionElem :: Downcast ( ..) , _) => bug ! (
527
+ "mismatched projections in place_element_conflict: {:?} and {:?}" ,
528
+ pi1,
529
+ pi2
580
530
) ,
581
531
}
582
532
}
0 commit comments