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