11use crate :: mir:: pretty:: { function_body, pretty_statement} ;
2- use crate :: ty:: { AdtDef , ClosureDef , Const , CoroutineDef , GenericArgs , Movability , Region , Ty } ;
3- use crate :: Opaque ;
4- use crate :: Span ;
2+ use crate :: ty:: {
3+ AdtDef , ClosureDef , Const , CoroutineDef , GenericArgs , Movability , Region , RigidTy , Ty , TyKind ,
4+ } ;
5+ use crate :: { Error , Opaque , Span } ;
56use std:: io;
7+
68/// The SMIR representation of a single function.
79#[ derive( Clone , Debug ) ]
810pub struct Body {
@@ -561,7 +563,7 @@ pub struct SwitchTarget {
561563 pub target : usize ,
562564}
563565
564- #[ derive( Clone , Debug , Eq , PartialEq ) ]
566+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
565567pub enum BorrowKind {
566568 /// Data must be immutable and is aliasable.
567569 Shared ,
@@ -579,14 +581,14 @@ pub enum BorrowKind {
579581 } ,
580582}
581583
582- #[ derive( Clone , Debug , Eq , PartialEq ) ]
584+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
583585pub enum MutBorrowKind {
584586 Default ,
585587 TwoPhaseBorrow ,
586588 ClosureCapture ,
587589}
588590
589- #[ derive( Clone , Debug , PartialEq , Eq ) ]
591+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
590592pub enum Mutability {
591593 Not ,
592594 Mut ,
@@ -651,10 +653,16 @@ pub enum NullOp {
651653}
652654
653655impl Operand {
654- pub fn ty ( & self , locals : & [ LocalDecl ] ) -> Ty {
656+ /// Get the type of an operand relative to the local declaration.
657+ ///
658+ /// In order to retrieve the correct type, the `locals` argument must match the list of all
659+ /// locals from the function body where this operand originates from.
660+ ///
661+ /// Errors indicate a malformed operand or incompatible locals list.
662+ pub fn ty ( & self , locals : & [ LocalDecl ] ) -> Result < Ty , Error > {
655663 match self {
656664 Operand :: Copy ( place) | Operand :: Move ( place) => place. ty ( locals) ,
657- Operand :: Constant ( c) => c. ty ( ) ,
665+ Operand :: Constant ( c) => Ok ( c. ty ( ) ) ,
658666 }
659667 }
660668}
@@ -666,12 +674,57 @@ impl Constant {
666674}
667675
668676impl Place {
669- // FIXME(klinvill): This function is expected to resolve down the chain of projections to get
670- // the type referenced at the end of it. E.g. calling `ty()` on `*(_1.f)` should end up
671- // returning the type referenced by `f`. The information needed to do this may not currently be
672- // present in Stable MIR since at least an implementation for AdtDef is probably needed.
673- pub fn ty ( & self , locals : & [ LocalDecl ] ) -> Ty {
674- let _start_ty = locals[ self . local ] . ty ;
675- todo ! ( "Implement projection" )
677+ /// Resolve down the chain of projections to get the type referenced at the end of it.
678+ /// E.g.:
679+ /// Calling `ty()` on `var.field` should return the type of `field`.
680+ ///
681+ /// In order to retrieve the correct type, the `locals` argument must match the list of all
682+ /// locals from the function body where this place originates from.
683+ pub fn ty ( & self , locals : & [ LocalDecl ] ) -> Result < Ty , Error > {
684+ let start_ty = locals[ self . local ] . ty ;
685+ self . projection . iter ( ) . fold ( Ok ( start_ty) , |place_ty, elem| {
686+ let ty = place_ty?;
687+ match elem {
688+ ProjectionElem :: Deref => Self :: deref_ty ( ty) ,
689+ ProjectionElem :: Field ( _idx, fty) => Ok ( * fty) ,
690+ ProjectionElem :: Index ( _) | ProjectionElem :: ConstantIndex { .. } => {
691+ Self :: index_ty ( ty)
692+ }
693+ ProjectionElem :: Subslice { from, to, from_end } => {
694+ Self :: subslice_ty ( ty, from, to, from_end)
695+ }
696+ ProjectionElem :: Downcast ( _) => Ok ( ty) ,
697+ ProjectionElem :: OpaqueCast ( ty) | ProjectionElem :: Subtype ( ty) => Ok ( * ty) ,
698+ }
699+ } )
700+ }
701+
702+ fn index_ty ( ty : Ty ) -> Result < Ty , Error > {
703+ ty. kind ( ) . builtin_index ( ) . ok_or_else ( || error ! ( "Cannot index non-array type: {ty:?}" ) )
704+ }
705+
706+ fn subslice_ty ( ty : Ty , from : & u64 , to : & u64 , from_end : & bool ) -> Result < Ty , Error > {
707+ let ty_kind = ty. kind ( ) ;
708+ match ty_kind {
709+ TyKind :: RigidTy ( RigidTy :: Slice ( ..) ) => Ok ( ty) ,
710+ TyKind :: RigidTy ( RigidTy :: Array ( inner, _) ) if !from_end => Ty :: try_new_array (
711+ inner,
712+ to. checked_sub ( * from) . ok_or_else ( || error ! ( "Subslice overflow: {from}..{to}" ) ) ?,
713+ ) ,
714+ TyKind :: RigidTy ( RigidTy :: Array ( inner, size) ) => {
715+ let size = size. eval_target_usize ( ) ?;
716+ let len = size - from - to;
717+ Ty :: try_new_array ( inner, len)
718+ }
719+ _ => Err ( Error ( format ! ( "Cannot subslice non-array type: `{ty_kind:?}`" ) ) ) ,
720+ }
721+ }
722+
723+ fn deref_ty ( ty : Ty ) -> Result < Ty , Error > {
724+ let deref_ty = ty
725+ . kind ( )
726+ . builtin_deref ( true )
727+ . ok_or_else ( || error ! ( "Cannot dereference type: {ty:?}" ) ) ?;
728+ Ok ( deref_ty. ty )
676729 }
677730}
0 commit comments