33//! corresponding to a single Rust expression.
44
55use super :: * ;
6+ use syn:: {
7+ Arm , ExprArray , ExprConst , ExprGroup , ExprIf , ExprMatch , ExprRange , ExprRawAddr , ExprReference ,
8+ ExprRepeat , ExprStruct , ExprTuple , ExprUnsafe , FieldValue ,
9+ } ;
610
711/// Check if something is a valid Rust lvalue. Inspired by `librustc::ty::expr_is_lval`.
812fn is_lvalue ( e : & Expr ) -> bool {
@@ -28,12 +32,95 @@ fn is_simple_lvalue(e: &Expr) -> bool {
2832 ref expr,
2933 ..
3034 } )
31- | Field ( ExprField { base : ref expr, .. } )
32- | Index ( ExprIndex { ref expr, .. } ) => is_simple_lvalue ( expr) ,
35+ | Field ( ExprField { base : ref expr, .. } ) => is_simple_lvalue ( expr) ,
36+ Index ( ExprIndex {
37+ ref expr,
38+ ref index,
39+ ..
40+ } ) => is_simple_lvalue ( expr) && !expr_has_side_effects ( index) ,
3341 _ => false ,
3442 }
3543}
3644
45+ /// Returns whether the expression has (or could have) any side effects.
46+ /// This is pessimistic, and does not cover all expression types currently.
47+ fn expr_has_side_effects ( expr : & Expr ) -> bool {
48+ use Expr :: * ;
49+
50+ match unparen ( expr) {
51+ Array ( ExprArray { elems, .. } ) => elems. iter ( ) . any ( |elem| expr_has_side_effects ( elem) ) ,
52+ Cast ( ExprCast { expr, .. } ) => expr_has_side_effects ( expr) ,
53+ Binary ( ExprBinary { left, right, .. } ) => {
54+ expr_has_side_effects ( left) || expr_has_side_effects ( right)
55+ }
56+ Block ( ExprBlock { block, .. } ) => block_has_side_effects ( block) ,
57+ Const ( ExprConst { block, .. } ) => block_has_side_effects ( block) ,
58+ Field ( ExprField { base, .. } ) => expr_has_side_effects ( base) ,
59+ Group ( ExprGroup { expr, .. } ) => expr_has_side_effects ( expr) ,
60+ Index ( ExprIndex { expr, index, .. } ) => {
61+ expr_has_side_effects ( expr) || expr_has_side_effects ( index)
62+ }
63+ Infer ( _) => false ,
64+ If ( ExprIf {
65+ cond,
66+ then_branch,
67+ else_branch,
68+ ..
69+ } ) => {
70+ expr_has_side_effects ( cond)
71+ || block_has_side_effects ( then_branch)
72+ || else_branch
73+ . as_ref ( )
74+ . map_or ( false , |( _, expr) | expr_has_side_effects ( expr) )
75+ }
76+ Lit ( _) => false ,
77+ Match ( ExprMatch { expr, arms, .. } ) => {
78+ expr_has_side_effects ( expr)
79+ || arms. iter ( ) . any ( |Arm { guard, body, .. } | {
80+ guard
81+ . as_ref ( )
82+ . map_or ( false , |( _, expr) | expr_has_side_effects ( expr) )
83+ || expr_has_side_effects ( body)
84+ } )
85+ }
86+ Paren ( ExprParen { expr, .. } ) => expr_has_side_effects ( expr) ,
87+ Path ( _) => false ,
88+ Range ( ExprRange { start, end, .. } ) => {
89+ start
90+ . as_ref ( )
91+ . map_or ( false , |expr| expr_has_side_effects ( expr) )
92+ || end
93+ . as_ref ( )
94+ . map_or ( false , |expr| expr_has_side_effects ( expr) )
95+ }
96+ RawAddr ( ExprRawAddr { expr, .. } ) => expr_has_side_effects ( expr) ,
97+ Reference ( ExprReference { expr, .. } ) => expr_has_side_effects ( expr) ,
98+ Repeat ( ExprRepeat { expr, len, .. } ) => {
99+ expr_has_side_effects ( expr) || expr_has_side_effects ( len)
100+ }
101+ Struct ( ExprStruct { fields, rest, .. } ) => {
102+ fields
103+ . iter ( )
104+ . any ( |FieldValue { expr, .. } | expr_has_side_effects ( expr) )
105+ || rest
106+ . as_ref ( )
107+ . map_or ( false , |rest| expr_has_side_effects ( rest) )
108+ }
109+ Tuple ( ExprTuple { elems, .. } ) => elems. iter ( ) . any ( |elem| expr_has_side_effects ( elem) ) ,
110+ Unary ( ExprUnary { expr, .. } ) => expr_has_side_effects ( expr) ,
111+ Unsafe ( ExprUnsafe { block, .. } ) => block_has_side_effects ( block) ,
112+ _ => true ,
113+ }
114+ }
115+
116+ fn block_has_side_effects ( block : & Block ) -> bool {
117+ use Stmt :: * ;
118+ block. stmts . iter ( ) . any ( |stmt| match stmt {
119+ Expr ( expr, _) => expr_has_side_effects ( expr) ,
120+ _ => true ,
121+ } )
122+ }
123+
37124pub struct NamedReference < R > {
38125 pub lvalue : Box < Expr > ,
39126 pub rvalue : R ,
0 commit comments