11use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
2+ use rustc_middle:: mir:: tcx:: PlaceTy ;
23use rustc_middle:: { mir:: * , thir:: * , ty} ;
4+ use rustc_span:: Span ;
5+ use rustc_target:: abi:: VariantIdx ;
6+
7+ use crate :: build:: custom:: ParseError ;
8+ use crate :: build:: expr:: as_constant:: as_constant_inner;
39
410use super :: { parse_by_kind, PResult , ParseCtxt } ;
511
@@ -12,6 +18,14 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
1218 @call( "mir_retag_raw" , args) => {
1319 Ok ( StatementKind :: Retag ( RetagKind :: Raw , Box :: new( self . parse_place( args[ 0 ] ) ?) ) )
1420 } ,
21+ @call( "mir_set_discriminant" , args) => {
22+ let place = self . parse_place( args[ 0 ] ) ?;
23+ let var = self . parse_integer_literal( args[ 1 ] ) ? as u32 ;
24+ Ok ( StatementKind :: SetDiscriminant {
25+ place: Box :: new( place) ,
26+ variant_index: VariantIdx :: from_u32( var) ,
27+ } )
28+ } ,
1529 ExprKind :: Assign { lhs, rhs } => {
1630 let lhs = self . parse_place( * lhs) ?;
1731 let rhs = self . parse_rvalue( * rhs) ?;
@@ -21,18 +35,60 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
2135 }
2236
2337 pub fn parse_terminator ( & self , expr_id : ExprId ) -> PResult < TerminatorKind < ' tcx > > {
24- parse_by_kind ! ( self , expr_id, _ , "terminator" ,
38+ parse_by_kind ! ( self , expr_id, expr , "terminator" ,
2539 @call( "mir_return" , _args) => {
2640 Ok ( TerminatorKind :: Return )
2741 } ,
2842 @call( "mir_goto" , args) => {
2943 Ok ( TerminatorKind :: Goto { target: self . parse_block( args[ 0 ] ) ? } )
3044 } ,
45+ ExprKind :: Match { scrutinee, arms } => {
46+ let discr = self . parse_operand( * scrutinee) ?;
47+ self . parse_match( arms, expr. span) . map( |t| TerminatorKind :: SwitchInt { discr, targets: t } )
48+ } ,
3149 )
3250 }
3351
52+ fn parse_match ( & self , arms : & [ ArmId ] , span : Span ) -> PResult < SwitchTargets > {
53+ let Some ( ( otherwise, rest) ) = arms. split_last ( ) else {
54+ return Err ( ParseError {
55+ span,
56+ item_description : format ! ( "no arms" ) ,
57+ expected : "at least one arm" . to_string ( ) ,
58+ } )
59+ } ;
60+
61+ let otherwise = & self . thir [ * otherwise] ;
62+ let PatKind :: Wild = otherwise. pattern . kind else {
63+ return Err ( ParseError {
64+ span : otherwise. span ,
65+ item_description : format ! ( "{:?}" , otherwise. pattern. kind) ,
66+ expected : "wildcard pattern" . to_string ( ) ,
67+ } )
68+ } ;
69+ let otherwise = self . parse_block ( otherwise. body ) ?;
70+
71+ let mut values = Vec :: new ( ) ;
72+ let mut targets = Vec :: new ( ) ;
73+ for arm in rest {
74+ let arm = & self . thir [ * arm] ;
75+ let PatKind :: Constant { value } = arm. pattern . kind else {
76+ return Err ( ParseError {
77+ span : arm. pattern . span ,
78+ item_description : format ! ( "{:?}" , arm. pattern. kind) ,
79+ expected : "constant pattern" . to_string ( ) ,
80+ } )
81+ } ;
82+ values. push ( value. eval_bits ( self . tcx , self . param_env , arm. pattern . ty ) ) ;
83+ targets. push ( self . parse_block ( arm. body ) ?) ;
84+ }
85+
86+ Ok ( SwitchTargets :: new ( values. into_iter ( ) . zip ( targets) , otherwise) )
87+ }
88+
3489 fn parse_rvalue ( & self , expr_id : ExprId ) -> PResult < Rvalue < ' tcx > > {
3590 parse_by_kind ! ( self , expr_id, _, "rvalue" ,
91+ @call( "mir_discriminant" , args) => self . parse_place( args[ 0 ] ) . map( Rvalue :: Discriminant ) ,
3692 ExprKind :: Borrow { borrow_kind, arg } => Ok (
3793 Rvalue :: Ref ( self . tcx. lifetimes. re_erased, * borrow_kind, self . parse_place( * arg) ?)
3894 ) ,
@@ -55,20 +111,50 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
55111 | ExprKind :: ConstParam { .. }
56112 | ExprKind :: ConstBlock { .. } => {
57113 Ok ( Operand :: Constant ( Box :: new(
58- crate :: build :: expr :: as_constant :: as_constant_inner( expr, |_| None , self . tcx)
114+ as_constant_inner( expr, |_| None , self . tcx)
59115 ) ) )
60116 } ,
61117 _ => self . parse_place( expr_id) . map( Operand :: Copy ) ,
62118 )
63119 }
64120
65121 fn parse_place ( & self , expr_id : ExprId ) -> PResult < Place < ' tcx > > {
66- parse_by_kind ! ( self , expr_id, _, "place" ,
67- ExprKind :: Deref { arg } => Ok (
68- self . parse_place( * arg) ?. project_deeper( & [ PlaceElem :: Deref ] , self . tcx)
69- ) ,
70- _ => self . parse_local( expr_id) . map( Place :: from) ,
71- )
122+ self . parse_place_inner ( expr_id) . map ( |( x, _) | x)
123+ }
124+
125+ fn parse_place_inner ( & self , expr_id : ExprId ) -> PResult < ( Place < ' tcx > , PlaceTy < ' tcx > ) > {
126+ let ( parent, proj) = parse_by_kind ! ( self , expr_id, expr, "place" ,
127+ @call( "mir_field" , args) => {
128+ let ( parent, ty) = self . parse_place_inner( args[ 0 ] ) ?;
129+ let field = Field :: from_u32( self . parse_integer_literal( args[ 1 ] ) ? as u32 ) ;
130+ let field_ty = ty. field_ty( self . tcx, field) ;
131+ let proj = PlaceElem :: Field ( field, field_ty) ;
132+ let place = parent. project_deeper( & [ proj] , self . tcx) ;
133+ return Ok ( ( place, PlaceTy :: from_ty( field_ty) ) ) ;
134+ } ,
135+ @call( "mir_variant" , args) => {
136+ ( args[ 0 ] , PlaceElem :: Downcast (
137+ None ,
138+ VariantIdx :: from_u32( self . parse_integer_literal( args[ 1 ] ) ? as u32 )
139+ ) )
140+ } ,
141+ ExprKind :: Deref { arg } => {
142+ parse_by_kind!( self , * arg, _, "does not matter" ,
143+ @call( "mir_make_place" , args) => return self . parse_place_inner( args[ 0 ] ) ,
144+ _ => ( * arg, PlaceElem :: Deref ) ,
145+ )
146+ } ,
147+ ExprKind :: Index { lhs, index } => ( * lhs, PlaceElem :: Index ( self . parse_local( * index) ?) ) ,
148+ ExprKind :: Field { lhs, name: field, .. } => ( * lhs, PlaceElem :: Field ( * field, expr. ty) ) ,
149+ _ => {
150+ let place = self . parse_local( expr_id) . map( Place :: from) ?;
151+ return Ok ( ( place, PlaceTy :: from_ty( expr. ty) ) )
152+ } ,
153+ ) ;
154+ let ( parent, ty) = self . parse_place_inner ( parent) ?;
155+ let place = parent. project_deeper ( & [ proj] , self . tcx ) ;
156+ let ty = ty. projection_ty ( self . tcx , proj) ;
157+ Ok ( ( place, ty) )
72158 }
73159
74160 fn parse_local ( & self , expr_id : ExprId ) -> PResult < Local > {
@@ -102,4 +188,16 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
102188 } ,
103189 )
104190 }
191+
192+ fn parse_integer_literal ( & self , expr_id : ExprId ) -> PResult < u128 > {
193+ parse_by_kind ! ( self , expr_id, expr, "constant" ,
194+ ExprKind :: Literal { .. }
195+ | ExprKind :: NamedConst { .. }
196+ | ExprKind :: NonHirLiteral { .. }
197+ | ExprKind :: ConstBlock { .. } => Ok ( {
198+ let value = as_constant_inner( expr, |_| None , self . tcx) ;
199+ value. literal. eval_bits( self . tcx, self . param_env, value. ty( ) )
200+ } ) ,
201+ )
202+ }
105203}
0 commit comments