]> git.lizzy.rs Git - rust.git/blob - src/librustc_const_math/int.rs
d97276da9bf34b9315d7a410f403fe34a558a076
[rust.git] / src / librustc_const_math / int.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::cmp::Ordering;
12 use syntax::attr::IntType;
13 use syntax::ast::{IntTy, UintTy};
14
15 use super::is::*;
16 use super::us::*;
17 use super::err::*;
18
19 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
20 pub enum ConstInt {
21     I8(i8),
22     I16(i16),
23     I32(i32),
24     I64(i64),
25     I128(i128),
26     Isize(ConstIsize),
27     U8(u8),
28     U16(u16),
29     U32(u32),
30     U64(u64),
31     U128(u128),
32     Usize(ConstUsize),
33 }
34 pub use self::ConstInt::*;
35
36
37 macro_rules! bounds {
38     ($ct: ty, $($t:ident $min:ident $max:ident)*) => {
39         $(
40             pub const $min: $ct = $t::min_value() as $ct;
41             pub const $max: $ct = $t::max_value() as $ct;
42         )*
43     };
44     ($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => {
45         $(
46             pub const $min: $ct = $min_val;
47             pub const $max: $ct = $t::max_value() as $ct;
48         )*
49     }
50 }
51
52 mod ubounds {
53     #![allow(dead_code)]
54     bounds!{u128: 0,
55         i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
56         u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX
57         // do not add constants for isize/usize, because these are guaranteed to be wrong for
58         // arbitrary host/target combinations
59     }
60 }
61
62 mod ibounds {
63     #![allow(dead_code)]
64     bounds!(i128, u64 U64MIN U64MAX);
65
66     pub const U128MIN: i128 = 0;
67     pub const U128MAX: i128 = i128::max_value();
68
69     bounds!{i128,
70         i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX
71         u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX
72         // do not add constants for isize/usize, because these are guaranteed to be wrong for
73         // arbitrary host/target combinations
74     }
75 }
76
77 impl ConstInt {
78     /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
79     /// not happen.
80     pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
81         match ty {
82             UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)),
83             UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)),
84             UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)),
85             UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)),
86             UintTy::Us if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok()
87                 .map(Usize),
88             UintTy::U128 => Some(U128(val)),
89             _ => None
90         }
91     }
92
93     /// Creates a new signed ConstInt with matching type while also checking that overflow does
94     /// not happen.
95     pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
96         match ty {
97             IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)),
98             IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)),
99             IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)),
100             IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)),
101             IntTy::Is if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok()
102                 .map(Isize),
103             IntTy::I128 => Some(I128(val)),
104             _ => None
105         }
106     }
107
108     /// Creates a new unsigned ConstInt with matching type.
109     pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
110         match ty {
111             UintTy::U8 => U8(val as u8),
112             UintTy::U16 => U16(val as u16),
113             UintTy::U32 => U32(val as u32),
114             UintTy::U64 => U64(val as u64),
115             UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)),
116             UintTy::U128 => U128(val)
117         }
118     }
119
120     /// Creates a new signed ConstInt with matching type.
121     pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
122         match ty {
123             IntTy::I8 => I8(val as i8),
124             IntTy::I16 => I16(val as i16),
125             IntTy::I32 => I32(val as i32),
126             IntTy::I64 => I64(val as i64),
127             IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)),
128             IntTy::I128 => I128(val)
129         }
130     }
131
132     /// Description of the type, not the value
133     pub fn description(&self) -> &'static str {
134         match *self {
135             I8(_) => "i8",
136             I16(_) => "i16",
137             I32(_) => "i32",
138             I64(_) => "i64",
139             I128(_) => "i128",
140             Isize(_) => "isize",
141             U8(_) => "u8",
142             U16(_) => "u16",
143             U32(_) => "u32",
144             U64(_) => "u64",
145             U128(_) => "u128",
146             Usize(_) => "usize",
147         }
148     }
149
150     /// Erases the type and returns a u128.
151     /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
152     pub fn to_u128_unchecked(self) -> u128 {
153         match self {
154             I8(i) => i as i128 as u128,
155             I16(i) => i as i128 as u128,
156             I32(i) => i as i128 as u128,
157             I64(i) => i as i128 as u128,
158             I128(i) => i as i128 as u128,
159             Isize(Is16(i)) => i as i128 as u128,
160             Isize(Is32(i)) => i as i128 as u128,
161             Isize(Is64(i)) => i as i128 as u128,
162             U8(i) => i as u128,
163             U16(i) => i as u128,
164             U32(i) => i as u128,
165             U64(i) => i as u128,
166             U128(i) => i as u128,
167             Usize(Us16(i)) => i as u128,
168             Usize(Us32(i)) => i as u128,
169             Usize(Us64(i)) => i as u128,
170         }
171     }
172
173     /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
174     pub fn to_u32(&self) -> Option<u32> {
175         self.to_u128().and_then(|v| if v <= u32::max_value() as u128 {
176             Some(v as u32)
177         } else {
178             None
179         })
180     }
181
182     /// Converts the value to a `u64` if it's in the range 0...std::u64::MAX
183     pub fn to_u64(&self) -> Option<u64> {
184         self.to_u128().and_then(|v| if v <= u64::max_value() as u128 {
185             Some(v as u64)
186         } else {
187             None
188         })
189     }
190
191     /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
192     pub fn to_u128(&self) -> Option<u128> {
193         match *self {
194             I8(v) if v >= 0 => Some(v as u128),
195             I16(v) if v >= 0 => Some(v as u128),
196             I32(v) if v >= 0 => Some(v as u128),
197             I64(v) if v >= 0 => Some(v as u128),
198             I128(v) if v >= 0 => Some(v as u128),
199             Isize(Is16(v)) if v >= 0 => Some(v as u128),
200             Isize(Is32(v)) if v >= 0 => Some(v as u128),
201             Isize(Is64(v)) if v >= 0 => Some(v as u128),
202             U8(v) => Some(v as u128),
203             U16(v) => Some(v as u128),
204             U32(v) => Some(v as u128),
205             U64(v) => Some(v as u128),
206             U128(v) => Some(v as u128),
207             Usize(Us16(v)) => Some(v as u128),
208             Usize(Us32(v)) => Some(v as u128),
209             Usize(Us64(v)) => Some(v as u128),
210             _ => None,
211         }
212     }
213
214     pub fn to_f32(self) -> f32 {
215         match self {
216             I8(i) => i as f32,
217             I16(i) => i as f32,
218             I32(i) => i as f32,
219             I64(i) => i as f32,
220             I128(i) => i as f32,
221             Isize(Is16(i)) => i as f32,
222             Isize(Is32(i)) => i as f32,
223             Isize(Is64(i)) => i as f32,
224             U8(i) => i as f32,
225             U16(i) => i as f32,
226             U32(i) => i as f32,
227             U64(i) => i as f32,
228             U128(i) => i as f32,
229             Usize(Us16(i)) => i as f32,
230             Usize(Us32(i)) => i as f32,
231             Usize(Us64(i)) => i as f32,
232         }
233     }
234
235     pub fn to_f64(self) -> f64 {
236         match self {
237             I8(i) => i as f64,
238             I16(i) => i as f64,
239             I32(i) => i as f64,
240             I64(i) => i as f64,
241             I128(i) => i as f64,
242             Isize(Is16(i)) => i as f64,
243             Isize(Is32(i)) => i as f64,
244             Isize(Is64(i)) => i as f64,
245             U8(i) => i as f64,
246             U16(i) => i as f64,
247             U32(i) => i as f64,
248             U64(i) => i as f64,
249             U128(i) => i as f64,
250             Usize(Us16(i)) => i as f64,
251             Usize(Us32(i)) => i as f64,
252             Usize(Us64(i)) => i as f64,
253         }
254     }
255
256     pub fn is_negative(&self) -> bool {
257         match *self {
258             I8(v) => v < 0,
259             I16(v) => v < 0,
260             I32(v) => v < 0,
261             I64(v) => v < 0,
262             I128(v) => v < 0,
263             Isize(Is16(v)) => v < 0,
264             Isize(Is32(v)) => v < 0,
265             Isize(Is64(v)) => v < 0,
266             _ => false,
267         }
268     }
269
270     /// Compares the values if they are of the same type
271     pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
272         match (self, rhs) {
273             (I8(a), I8(b)) => Ok(a.cmp(&b)),
274             (I16(a), I16(b)) => Ok(a.cmp(&b)),
275             (I32(a), I32(b)) => Ok(a.cmp(&b)),
276             (I64(a), I64(b)) => Ok(a.cmp(&b)),
277             (I128(a), I128(b)) => Ok(a.cmp(&b)),
278             (Isize(Is16(a)), Isize(Is16(b))) => Ok(a.cmp(&b)),
279             (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
280             (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
281             (U8(a), U8(b)) => Ok(a.cmp(&b)),
282             (U16(a), U16(b)) => Ok(a.cmp(&b)),
283             (U32(a), U32(b)) => Ok(a.cmp(&b)),
284             (U64(a), U64(b)) => Ok(a.cmp(&b)),
285             (U128(a), U128(b)) => Ok(a.cmp(&b)),
286             (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
287             (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
288             (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
289             _ => Err(CmpBetweenUnequalTypes),
290         }
291     }
292
293     /// Adds 1 to the value and wraps around if the maximum for the type is reached
294     pub fn wrap_incr(self) -> Self {
295         macro_rules! add1 {
296             ($e:expr) => { ($e).wrapping_add(1) }
297         }
298         match self {
299             ConstInt::I8(i) => ConstInt::I8(add1!(i)),
300             ConstInt::I16(i) => ConstInt::I16(add1!(i)),
301             ConstInt::I32(i) => ConstInt::I32(add1!(i)),
302             ConstInt::I64(i) => ConstInt::I64(add1!(i)),
303             ConstInt::I128(i) => ConstInt::I128(add1!(i)),
304             ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))),
305             ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
306             ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
307             ConstInt::U8(i) => ConstInt::U8(add1!(i)),
308             ConstInt::U16(i) => ConstInt::U16(add1!(i)),
309             ConstInt::U32(i) => ConstInt::U32(add1!(i)),
310             ConstInt::U64(i) => ConstInt::U64(add1!(i)),
311             ConstInt::U128(i) => ConstInt::U128(add1!(i)),
312             ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
313             ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
314             ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
315         }
316     }
317
318     pub fn int_type(self) -> IntType {
319         match self {
320             ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
321             ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
322             ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
323             ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
324             ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
325             ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is),
326             ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
327             ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
328             ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
329             ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
330             ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
331             ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us),
332         }
333     }
334 }
335
336 impl ::std::cmp::PartialOrd for ConstInt {
337     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
338         self.try_cmp(*other).ok()
339     }
340 }
341
342 impl ::std::cmp::Ord for ConstInt {
343     fn cmp(&self, other: &Self) -> Ordering {
344         self.try_cmp(*other).unwrap()
345     }
346 }
347
348 impl ::std::fmt::Display for ConstInt {
349     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
350         match *self {
351             I8(i) => write!(fmt, "{}i8", i),
352             I16(i) => write!(fmt, "{}i16", i),
353             I32(i) => write!(fmt, "{}i32", i),
354             I64(i) => write!(fmt, "{}i64", i),
355             I128(i) => write!(fmt, "{}i128", i),
356             Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
357             Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i),
358             Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i),
359             U8(i) => write!(fmt, "{}u8", i),
360             U16(i) => write!(fmt, "{}u16", i),
361             U32(i) => write!(fmt, "{}u32", i),
362             U64(i) => write!(fmt, "{}u64", i),
363             U128(i) => write!(fmt, "{}u128", i),
364             Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
365             Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
366             Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i),
367         }
368     }
369 }
370
371 macro_rules! overflowing {
372     ($e:expr, $err:expr) => {{
373         if $e.1 {
374             return Err(Overflow($err));
375         } else {
376             $e.0
377         }
378     }}
379 }
380
381 macro_rules! impl_binop {
382     ($op:ident, $func:ident, $checked_func:ident) => {
383         impl ::std::ops::$op for ConstInt {
384             type Output = Result<Self, ConstMathErr>;
385             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
386                 match (self, rhs) {
387                     (I8(a), I8(b)) => a.$checked_func(b).map(I8),
388                     (I16(a), I16(b)) => a.$checked_func(b).map(I16),
389                     (I32(a), I32(b)) => a.$checked_func(b).map(I32),
390                     (I64(a), I64(b)) => a.$checked_func(b).map(I64),
391                     (I128(a), I128(b)) => a.$checked_func(b).map(I128),
392                     (Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize),
393                     (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
394                     (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
395                     (U8(a), U8(b)) => a.$checked_func(b).map(U8),
396                     (U16(a), U16(b)) => a.$checked_func(b).map(U16),
397                     (U32(a), U32(b)) => a.$checked_func(b).map(U32),
398                     (U64(a), U64(b)) => a.$checked_func(b).map(U64),
399                     (U128(a), U128(b)) => a.$checked_func(b).map(U128),
400                     (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
401                     (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
402                     (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
403                     _ => return Err(UnequalTypes(Op::$op)),
404                 }.ok_or(Overflow(Op::$op))
405             }
406         }
407     }
408 }
409
410 macro_rules! derive_binop {
411     ($op:ident, $func:ident) => {
412         impl ::std::ops::$op for ConstInt {
413             type Output = Result<Self, ConstMathErr>;
414             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
415                 match (self, rhs) {
416                     (I8(a), I8(b)) => Ok(I8(a.$func(b))),
417                     (I16(a), I16(b)) => Ok(I16(a.$func(b))),
418                     (I32(a), I32(b)) => Ok(I32(a.$func(b))),
419                     (I64(a), I64(b)) => Ok(I64(a.$func(b))),
420                     (I128(a), I128(b)) => Ok(I128(a.$func(b))),
421                     (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a.$func(b)))),
422                     (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
423                     (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
424                     (U8(a), U8(b)) => Ok(U8(a.$func(b))),
425                     (U16(a), U16(b)) => Ok(U16(a.$func(b))),
426                     (U32(a), U32(b)) => Ok(U32(a.$func(b))),
427                     (U64(a), U64(b)) => Ok(U64(a.$func(b))),
428                     (U128(a), U128(b)) => Ok(U128(a.$func(b))),
429                     (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
430                     (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
431                     (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
432                     _ => Err(UnequalTypes(Op::$op)),
433                 }
434             }
435         }
436     }
437 }
438
439 impl_binop!(Add, add, checked_add);
440 impl_binop!(Sub, sub, checked_sub);
441 impl_binop!(Mul, mul, checked_mul);
442 derive_binop!(BitAnd, bitand);
443 derive_binop!(BitOr, bitor);
444 derive_binop!(BitXor, bitxor);
445
446 const I128_MIN: i128 = ::std::i128::MIN;
447
448 fn check_division(
449     lhs: ConstInt,
450     rhs: ConstInt,
451     op: Op,
452     zerr: ConstMathErr,
453 ) -> Result<(), ConstMathErr> {
454     match (lhs, rhs) {
455         (I8(_), I8(0)) => Err(zerr),
456         (I16(_), I16(0)) => Err(zerr),
457         (I32(_), I32(0)) => Err(zerr),
458         (I64(_), I64(0)) => Err(zerr),
459         (I128(_), I128(0)) => Err(zerr),
460         (Isize(_), Isize(Is16(0))) => Err(zerr),
461         (Isize(_), Isize(Is32(0))) => Err(zerr),
462         (Isize(_), Isize(Is64(0))) => Err(zerr),
463
464         (U8(_), U8(0)) => Err(zerr),
465         (U16(_), U16(0)) => Err(zerr),
466         (U32(_), U32(0)) => Err(zerr),
467         (U64(_), U64(0)) => Err(zerr),
468         (U128(_), U128(0)) => Err(zerr),
469         (Usize(_), Usize(Us16(0))) => Err(zerr),
470         (Usize(_), Usize(Us32(0))) => Err(zerr),
471         (Usize(_), Usize(Us64(0))) => Err(zerr),
472
473         (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
474         (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
475         (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
476         (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
477         (I128(I128_MIN), I128(-1)) => Err(Overflow(op)),
478         (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
479         (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
480         (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
481
482         _ => Ok(()),
483     }
484 }
485
486 impl ::std::ops::Div for ConstInt {
487     type Output = Result<Self, ConstMathErr>;
488     fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
489         let (lhs, rhs) = (self, rhs);
490         check_division(lhs, rhs, Op::Div, DivisionByZero)?;
491         match (lhs, rhs) {
492             (I8(a), I8(b)) => Ok(I8(a/b)),
493             (I16(a), I16(b)) => Ok(I16(a/b)),
494             (I32(a), I32(b)) => Ok(I32(a/b)),
495             (I64(a), I64(b)) => Ok(I64(a/b)),
496             (I128(a), I128(b)) => Ok(I128(a/b)),
497             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
498             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
499             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
500
501             (U8(a), U8(b)) => Ok(U8(a/b)),
502             (U16(a), U16(b)) => Ok(U16(a/b)),
503             (U32(a), U32(b)) => Ok(U32(a/b)),
504             (U64(a), U64(b)) => Ok(U64(a/b)),
505             (U128(a), U128(b)) => Ok(U128(a/b)),
506             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
507             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
508             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
509
510             _ => Err(UnequalTypes(Op::Div)),
511         }
512     }
513 }
514
515 impl ::std::ops::Rem for ConstInt {
516     type Output = Result<Self, ConstMathErr>;
517     fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
518         let (lhs, rhs) = (self, rhs);
519         // should INT_MIN%-1 be zero or an error?
520         check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
521         match (lhs, rhs) {
522             (I8(a), I8(b)) => Ok(I8(a%b)),
523             (I16(a), I16(b)) => Ok(I16(a%b)),
524             (I32(a), I32(b)) => Ok(I32(a%b)),
525             (I64(a), I64(b)) => Ok(I64(a%b)),
526             (I128(a), I128(b)) => Ok(I128(a%b)),
527             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
528             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
529             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
530
531             (U8(a), U8(b)) => Ok(U8(a%b)),
532             (U16(a), U16(b)) => Ok(U16(a%b)),
533             (U32(a), U32(b)) => Ok(U32(a%b)),
534             (U64(a), U64(b)) => Ok(U64(a%b)),
535             (U128(a), U128(b)) => Ok(U128(a%b)),
536             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
537             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
538             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
539
540             _ => Err(UnequalTypes(Op::Rem)),
541         }
542     }
543 }
544
545 impl ::std::ops::Shl<ConstInt> for ConstInt {
546     type Output = Result<Self, ConstMathErr>;
547     fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
548         let b = rhs.to_u32().ok_or(ShiftNegative)?;
549         match self {
550             I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
551             I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
552             I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
553             I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
554             I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))),
555             Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
556             Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
557             Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
558             U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
559             U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
560             U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
561             U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
562             U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))),
563             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
564             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
565             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
566         }
567     }
568 }
569
570 impl ::std::ops::Shr<ConstInt> for ConstInt {
571     type Output = Result<Self, ConstMathErr>;
572     fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
573         let b = rhs.to_u32().ok_or(ShiftNegative)?;
574         match self {
575             I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
576             I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
577             I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
578             I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))),
579             I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))),
580             Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
581             Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
582             Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
583             U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
584             U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
585             U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
586             U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
587             U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))),
588             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
589             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
590             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
591         }
592     }
593 }
594
595 impl ::std::ops::Neg for ConstInt {
596     type Output = Result<Self, ConstMathErr>;
597     fn neg(self) -> Result<Self, ConstMathErr> {
598         match self {
599             I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
600             I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
601             I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
602             I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
603             I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))),
604             Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_neg(), Op::Neg)))),
605             Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
606             Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
607             a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
608             a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
609             U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
610         }
611     }
612 }
613
614 impl ::std::ops::Not for ConstInt {
615     type Output = Result<Self, ConstMathErr>;
616     fn not(self) -> Result<Self, ConstMathErr> {
617         match self {
618             I8(a) => Ok(I8(!a)),
619             I16(a) => Ok(I16(!a)),
620             I32(a) => Ok(I32(!a)),
621             I64(a) => Ok(I64(!a)),
622             I128(a) => Ok(I128(!a)),
623             Isize(Is16(a)) => Ok(Isize(Is16(!a))),
624             Isize(Is32(a)) => Ok(Isize(Is32(!a))),
625             Isize(Is64(a)) => Ok(Isize(Is64(!a))),
626             U8(a) => Ok(U8(!a)),
627             U16(a) => Ok(U16(!a)),
628             U32(a) => Ok(U32(!a)),
629             U64(a) => Ok(U64(!a)),
630             U128(a) => Ok(U128(!a)),
631             Usize(Us16(a)) => Ok(Usize(Us16(!a))),
632             Usize(Us32(a)) => Ok(Usize(Us32(!a))),
633             Usize(Us64(a)) => Ok(Usize(Us64(!a))),
634         }
635     }
636 }