@@ -103,78 +103,66 @@ impl Tree {
103103 right. as_ref ( ) ?. eval ( )
104104 }
105105 }
106+
107+ #[ allow( clippy:: enum_glob_use) ]
108+ #[ allow( clippy:: float_cmp) ] // We want to match the Nix reference implementation
106109 TreeSource :: BinOp { op, left, right } => {
107110 use BinOpKind :: * ;
108111 use NixValue :: * ;
109- let tmp1 = left. as_ref ( ) ?. eval ( ) ?;
110- let tmp2 = right. as_ref ( ) ?. eval ( ) ?;
111- let left = tmp1. borrow ( ) ;
112- let right = tmp2. borrow ( ) ;
113- let out = match ( op, left, right) {
114- ( Add , Integer ( x) , Integer ( y) ) => Integer ( x + y) ,
115- ( Add , Float ( x) , Float ( y) ) => Float ( x + y) ,
116- ( Add , Integer ( x) , Float ( y) ) => Float ( * x as f64 + y) ,
117- ( Add , Float ( x) , Integer ( y) ) => Float ( x + * y as f64 ) ,
118-
119- ( Sub , Integer ( x) , Integer ( y) ) => Integer ( x - y) ,
120- ( Sub , Float ( x) , Float ( y) ) => Float ( x - y) ,
121- ( Sub , Integer ( x) , Float ( y) ) => Float ( * x as f64 - y) ,
122- ( Sub , Float ( x) , Integer ( y) ) => Float ( x - * y as f64 ) ,
123-
124- ( Mul , Integer ( x) , Integer ( y) ) => Integer ( x * y) ,
125- ( Mul , Float ( x) , Float ( y) ) => Float ( x * y) ,
126- ( Mul , Integer ( x) , Float ( y) ) => Float ( * x as f64 * y) ,
127- ( Mul , Float ( x) , Integer ( y) ) => Float ( x * * y as f64 ) ,
128-
129- ( Div , Integer ( x) , Integer ( y) ) => Integer (
130- x. checked_div ( * y)
131- . ok_or_else ( || EvalError :: Unexpected ( "division by zero" . to_string ( ) ) ) ?,
132- ) ,
133- ( Div , Float ( x) , Float ( y) ) => Float ( x / y) ,
134- ( Div , Integer ( x) , Float ( y) ) => Float ( * x as f64 / y) ,
135- ( Div , Float ( x) , Integer ( y) ) => Float ( x / * y as f64 ) ,
136-
137- // It seems like the Nix reference implementation compares floats exactly
138- // https://github.com/NixOS/nix/blob/4a5aa1dbf6/src/libutil/comparator.hh#L26
139- ( Equal , Integer ( x) , Integer ( y) ) => Bool ( x == y) ,
140- ( Equal , Float ( x) , Float ( y) ) => Bool ( x == y) ,
141- ( Equal , Integer ( x) , Float ( y) ) => Bool ( * x as f64 == * y) ,
142- ( Equal , Float ( x) , Integer ( y) ) => Bool ( * x == * y as f64 ) ,
143- ( Equal , Bool ( x) , Bool ( y) ) => Bool ( x == y) ,
144112
145- ( NotEqual , Integer ( x) , Integer ( y) ) => Bool ( x != y) ,
146- ( NotEqual , Float ( x) , Float ( y) ) => Bool ( x != y) ,
147- ( NotEqual , Integer ( x) , Float ( y) ) => Bool ( * x as f64 != * y) ,
148- ( NotEqual , Float ( x) , Integer ( y) ) => Bool ( * x != * y as f64 ) ,
149- ( NotEqual , Bool ( x) , Bool ( y) ) => Bool ( x != y) ,
113+ // Workaround for "temporary value dropped while borrowed"
114+ // https://doc.rust-lang.org/error-index.html#E0716
115+ let left_tmp = left. as_ref ( ) ?. eval ( ) ?;
116+ let left_val = left_tmp. borrow ( ) ;
117+ let right_tmp = right. as_ref ( ) ?. eval ( ) ?;
118+ let right_val = right_tmp. borrow ( ) ;
150119
151- ( Less , Integer ( x) , Integer ( y) ) => Bool ( x < y) ,
152- ( Less , Float ( x) , Float ( y) ) => Bool ( x < y) ,
153- ( Less , Integer ( x) , Float ( y) ) => Bool ( ( * x as f64 ) < * y) ,
154- ( Less , Float ( x) , Integer ( y) ) => Bool ( * x < * y as f64 ) ,
155-
156- ( LessOrEq , Integer ( x) , Integer ( y) ) => Bool ( x <= y) ,
157- ( LessOrEq , Float ( x) , Float ( y) ) => Bool ( x <= y) ,
158- ( LessOrEq , Integer ( x) , Float ( y) ) => Bool ( * x as f64 <= * y) ,
159- ( LessOrEq , Float ( x) , Integer ( y) ) => Bool ( * x <= * y as f64 ) ,
160-
161- ( Greater , Integer ( x) , Integer ( y) ) => Bool ( x > y) ,
162- ( Greater , Float ( x) , Float ( y) ) => Bool ( x > y) ,
163- ( Greater , Integer ( x) , Float ( y) ) => Bool ( * x as f64 > * y) ,
164- ( Greater , Float ( x) , Integer ( y) ) => Bool ( * x > ( * y as f64 ) ) ,
120+ // Specially handle integer division by zero
121+ if let ( Div , Integer ( _) , Integer ( 0 ) ) = ( op, left_val, right_val) {
122+ return Err ( EvalError :: Unexpected ( "division by zero" . to_string ( ) ) ) ;
123+ }
165124
166- ( GreaterOrEq , Integer ( x) , Integer ( y) ) => Bool ( x >= y) ,
167- ( GreaterOrEq , Float ( x) , Float ( y) ) => Bool ( x >= y) ,
168- ( GreaterOrEq , Integer ( x) , Float ( y) ) => Bool ( * x as f64 >= * y) ,
169- ( GreaterOrEq , Float ( x) , Integer ( y) ) => Bool ( * x >= ( * y as f64 ) ) ,
125+ macro_rules! match_binops {
126+ ( arithmetic [ $( $arith_kind: pat => $arith_oper: tt, ) + ] ,
127+ comparisons [ $( $comp_kind: pat => $comp_oper: tt, ) + ] ,
128+ $( $pattern: pat => $expr: expr ) ,* ) => {
129+ match ( op, left_val, right_val) {
130+ $(
131+ ( $arith_kind, Integer ( x) , Integer ( y) ) => Integer ( x $arith_oper y) ,
132+ ( $arith_kind, Float ( x) , Float ( y) ) => Float ( x $arith_oper y) ,
133+ ( $arith_kind, Integer ( x) , Float ( y) ) => Float ( ( * x as f64 ) $arith_oper y) ,
134+ ( $arith_kind, Float ( x) , Integer ( y) ) => Float ( x $arith_oper ( * y as f64 ) ) ,
135+ ) *
136+ $(
137+ ( $comp_kind, Integer ( x) , Integer ( y) ) => Bool ( x $comp_oper y) ,
138+ ( $comp_kind, Float ( x) , Float ( y) ) => Bool ( x $comp_oper y) ,
139+ ( $comp_kind, Integer ( x) , Float ( y) ) => Bool ( ( * x as f64 ) $comp_oper * y) ,
140+ ( $comp_kind, Float ( x) , Integer ( y) ) => Bool ( * x $comp_oper ( * y as f64 ) ) ,
141+ ) *
142+ $(
143+ $pattern => $expr,
144+ ) *
145+ }
146+ } ;
147+ }
170148
149+ let out = match_binops ! {
150+ arithmetic [
151+ Add => +, Sub => -, Mul => * , Div => /,
152+ ] ,
153+ comparisons [
154+ Equal => ==, NotEqual => !=,
155+ Greater => >, GreaterOrEq => >=,
156+ Less => <, LessOrEq => <=,
157+ ] ,
171158 _ => {
172159 return Err ( EvalError :: Unexpected ( format!(
173160 "{:?} {:?} {:?} unsupported" ,
174161 left, op, right
175162 ) ) )
176163 }
177164 } ;
165+
178166 Ok ( Gc :: new ( out) )
179167 }
180168 TreeSource :: UnaryInvert { value } => {
0 commit comments