@@ -398,22 +398,133 @@ pub enum Operand {
398
398
pub struct Place {
399
399
pub local : Local ,
400
400
/// projection out of a place (access a field, deref a pointer, etc)
401
- pub projection : String ,
401
+ pub projection : Vec < ProjectionElem < Local , Ty > > ,
402
+ }
403
+
404
+ // TODO(klinvill): in MIR ProjectionElem is parameterized on the second Field argument and the Index
405
+ // argument. This is so it can be used for both the rust provided Places (for which the projection
406
+ // elements are of type ProjectionElem<Local, Ty>) and user-provided type annotations (for which the
407
+ // projection elements are of type ProjectionElem<(), ()>). Should we do the same thing in Stable MIR?
408
+ #[ derive( Clone , Debug ) ]
409
+ pub enum ProjectionElem < V , T > {
410
+ /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place.
411
+ Deref ,
412
+
413
+ /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is
414
+ /// referenced by source-order index rather than the name of the field. The fields type is also
415
+ /// given.
416
+ Field ( FieldIdx , T ) ,
417
+
418
+ /// Index into a slice/array. The value of the index is computed at runtime using the `V`
419
+ /// argument.
420
+ ///
421
+ /// Note that this does not also dereference, and so it does not exactly correspond to slice
422
+ /// indexing in Rust. In other words, in the below Rust code:
423
+ ///
424
+ /// ```rust
425
+ /// let x = &[1, 2, 3, 4];
426
+ /// let i = 2;
427
+ /// x[i];
428
+ /// ```
429
+ ///
430
+ /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same
431
+ /// thing is true of the `ConstantIndex` and `Subslice` projections below.
432
+ Index ( V ) ,
433
+
434
+ /// Index into a slice/array given by offsets.
435
+ ///
436
+ /// These indices are generated by slice patterns. Easiest to explain by example:
437
+ ///
438
+ /// ```ignore (illustrative)
439
+ /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false },
440
+ /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false },
441
+ /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true },
442
+ /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true },
443
+ /// ```
444
+ ConstantIndex {
445
+ /// index or -index (in Python terms), depending on from_end
446
+ offset : u64 ,
447
+ /// The thing being indexed must be at least this long. For arrays this
448
+ /// is always the exact length.
449
+ min_length : u64 ,
450
+ /// Counting backwards from end? This is always false when indexing an
451
+ /// array.
452
+ from_end : bool ,
453
+ } ,
454
+
455
+ /// Projects a slice from the base place.
456
+ ///
457
+ /// These indices are generated by slice patterns. If `from_end` is true, this represents
458
+ /// `slice[from..slice.len() - to]`. Otherwise it represents `array[from..to]`.
459
+ Subslice {
460
+ from : u64 ,
461
+ to : u64 ,
462
+ /// Whether `to` counts from the start or end of the array/slice.
463
+ from_end : bool ,
464
+ } ,
465
+
466
+ /// "Downcast" to a variant of an enum or a coroutine.
467
+ //
468
+ // TODO(klinvill): MIR includes an Option<Symbol> argument that is the name of the variant, used
469
+ // for printing MIR. However I don't see it used anywhere. Is such a field needed or can we just
470
+ // include the VariantIdx which could be used to recover the field name if needed?
471
+ Downcast ( VariantIdx ) ,
472
+
473
+ /// Like an explicit cast from an opaque type to a concrete type, but without
474
+ /// requiring an intermediate variable.
475
+ OpaqueCast ( T ) ,
476
+
477
+ /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
478
+ /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
479
+ /// explicit during optimizations and codegen.
480
+ ///
481
+ /// This projection doesn't impact the runtime behavior of the program except for potentially changing
482
+ /// some type metadata of the interpreter or codegen backend.
483
+ Subtype ( T ) ,
402
484
}
403
485
404
486
#[ derive( Clone , Debug , Eq , PartialEq ) ]
405
487
pub struct UserTypeProjection {
406
488
pub base : UserTypeAnnotationIndex ,
407
- pub projection : String ,
489
+
490
+ /// `UserTypeProjection` projections need neither the `V` parameter for `Index` nor the `T` for
491
+ /// `Field`.
492
+ pub projection : Vec < ProjectionElem < ( ) , ( ) > > ,
408
493
}
409
494
410
495
pub type Local = usize ;
411
496
412
497
pub const RETURN_LOCAL : Local = 0 ;
413
498
499
+ /// The source-order index of a field in a variant.
500
+ ///
501
+ /// For example, in the following types,
502
+ /// ```rust
503
+ /// enum Demo1 {
504
+ /// Variant0 { a: bool, b: i32 },
505
+ /// Variant1 { c: u8, d: u64 },
506
+ /// }
507
+ /// struct Demo2 { e: u8, f: u16, g: u8 }
508
+ /// ```
509
+ /// `a`'s `FieldIdx` is `0`,
510
+ /// `b`'s `FieldIdx` is `1`,
511
+ /// `c`'s `FieldIdx` is `0`, and
512
+ /// `g`'s `FieldIdx` is `2`.
414
513
type FieldIdx = usize ;
415
514
416
515
/// The source-order index of a variant in a type.
516
+ ///
517
+ /// For example, in the following types,
518
+ /// ```rust
519
+ /// enum Demo1 {
520
+ /// Variant0 { a: bool, b: i32 },
521
+ /// Variant1 { c: u8, d: u64 },
522
+ /// }
523
+ /// struct Demo2 { e: u8, f: u16, g: u8 }
524
+ /// ```
525
+ /// `a` is in the variant with the `VariantIdx` of `0`,
526
+ /// `c` is in the variant with the `VariantIdx` of `1`, and
527
+ /// `g` is in the variant with the `VariantIdx` of `0`.
417
528
pub type VariantIdx = usize ;
418
529
419
530
type UserTypeAnnotationIndex = usize ;
@@ -536,6 +647,8 @@ impl Constant {
536
647
}
537
648
538
649
impl Place {
650
+ // TODO(klinvill): What is the expected behavior of this function? Should it resolve down the
651
+ // chain of projections so that `*(_1.f)` would end up returning the type referenced by `f`?
539
652
pub fn ty ( & self , locals : & [ LocalDecl ] ) -> Ty {
540
653
let _start_ty = locals[ self . local ] . ty ;
541
654
todo ! ( "Implement projection" )
0 commit comments