@@ -398,22 +398,133 @@ pub enum Operand {
398398pub struct Place {
399399 pub local : Local ,
400400 /// 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 ) ,
402484}
403485
404486#[ derive( Clone , Debug , Eq , PartialEq ) ]
405487pub struct UserTypeProjection {
406488 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 < ( ) , ( ) > > ,
408493}
409494
410495pub type Local = usize ;
411496
412497pub const RETURN_LOCAL : Local = 0 ;
413498
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`.
414513type FieldIdx = usize ;
415514
416515/// 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`.
417528pub type VariantIdx = usize ;
418529
419530type UserTypeAnnotationIndex = usize ;
@@ -536,6 +647,8 @@ impl Constant {
536647}
537648
538649impl 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`?
539652 pub fn ty ( & self , locals : & [ LocalDecl ] ) -> Ty {
540653 let _start_ty = locals[ self . local ] . ty ;
541654 todo ! ( "Implement projection" )
0 commit comments