1use super::{
4 ast::{Diagnostic, Expression, Namespace, Type},
5 diagnostics::Diagnostics,
6};
7use num_bigint::BigInt;
8use num_bigint::Sign;
9use num_rational::BigRational;
10use num_traits::One;
11use num_traits::ToPrimitive;
12use num_traits::Zero;
13use solang_parser::pt;
14use solang_parser::pt::{CodeLocation, Loc};
15use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Shl, Shr, Sub};
16
17pub fn eval_const_number(
19 expr: &Expression,
20 ns: &Namespace,
21 diagnostics: &mut Diagnostics,
22) -> Result<(pt::Loc, BigInt), ()> {
23 match expr {
24 Expression::Add {
25 loc, left, right, ..
26 } => Ok((
27 *loc,
28 eval_const_number(left, ns, diagnostics)?.1
29 + eval_const_number(right, ns, diagnostics)?.1,
30 )),
31 Expression::Subtract {
32 loc, left, right, ..
33 } => Ok((
34 *loc,
35 eval_const_number(left, ns, diagnostics)?.1
36 - eval_const_number(right, ns, diagnostics)?.1,
37 )),
38 Expression::Multiply {
39 loc, left, right, ..
40 } => Ok((
41 *loc,
42 eval_const_number(left, ns, diagnostics)?.1
43 * eval_const_number(right, ns, diagnostics)?.1,
44 )),
45 Expression::Divide {
46 loc, left, right, ..
47 } => {
48 let divisor = eval_const_number(right, ns, diagnostics)?.1;
49
50 if divisor.is_zero() {
51 diagnostics.push(Diagnostic::error(*loc, "divide by zero".to_string()));
52
53 Err(())
54 } else {
55 Ok((*loc, eval_const_number(left, ns, diagnostics)?.1 / divisor))
56 }
57 }
58 Expression::Modulo {
59 loc, left, right, ..
60 } => {
61 let divisor = eval_const_number(right, ns, diagnostics)?.1;
62
63 if divisor.is_zero() {
64 diagnostics.push(Diagnostic::error(*loc, "divide by zero".to_string()));
65
66 Err(())
67 } else {
68 Ok((*loc, eval_const_number(left, ns, diagnostics)?.1 % divisor))
69 }
70 }
71 Expression::BitwiseAnd {
72 loc, left, right, ..
73 } => Ok((
74 *loc,
75 eval_const_number(left, ns, diagnostics)?.1
76 & eval_const_number(right, ns, diagnostics)?.1,
77 )),
78 Expression::BitwiseOr {
79 loc, left, right, ..
80 } => Ok((
81 *loc,
82 eval_const_number(left, ns, diagnostics)?.1
83 | eval_const_number(right, ns, diagnostics)?.1,
84 )),
85 Expression::BitwiseXor {
86 loc, left, right, ..
87 } => Ok((
88 *loc,
89 eval_const_number(left, ns, diagnostics)?.1
90 ^ eval_const_number(right, ns, diagnostics)?.1,
91 )),
92 Expression::Power { loc, base, exp, .. } => {
93 let b = eval_const_number(base, ns, diagnostics)?.1;
94 let mut e = eval_const_number(exp, ns, diagnostics)?.1;
95
96 if e.sign() == Sign::Minus {
97 diagnostics.push(Diagnostic::error(
98 *loc,
99 "power cannot take negative number as exponent".to_string(),
100 ));
101
102 Err(())
103 } else if e.sign() == Sign::NoSign {
104 Ok((*loc, BigInt::one()))
105 } else {
106 let mut res = b.clone();
107 e -= BigInt::one();
108 while e.sign() == Sign::Plus {
109 res *= b.clone();
110 e -= BigInt::one();
111 }
112 Ok((*loc, res))
113 }
114 }
115 Expression::ShiftLeft {
116 loc, left, right, ..
117 } => {
118 let l = eval_const_number(left, ns, diagnostics)?.1;
119 let r = eval_const_number(right, ns, diagnostics)?.1;
120 let r = match r.to_usize() {
121 Some(r) => r,
122 None => {
123 diagnostics.push(Diagnostic::error(*loc, format!("cannot left shift by {r}")));
124
125 return Err(());
126 }
127 };
128 Ok((*loc, l << r))
129 }
130 Expression::ShiftRight {
131 loc, left, right, ..
132 } => {
133 let l = eval_const_number(left, ns, diagnostics)?.1;
134 let r = eval_const_number(right, ns, diagnostics)?.1;
135 let r = match r.to_usize() {
136 Some(r) => r,
137 None => {
138 diagnostics.push(Diagnostic::error(*loc, format!("right left shift by {r}")));
139
140 return Err(());
141 }
142 };
143 Ok((*loc, l >> r))
144 }
145 Expression::NumberLiteral { loc, value, .. } => Ok((*loc, value.clone())),
146 Expression::ZeroExt { loc, expr, .. } => {
147 Ok((*loc, eval_const_number(expr, ns, diagnostics)?.1))
148 }
149 Expression::SignExt { loc, expr, .. } => {
150 Ok((*loc, eval_const_number(expr, ns, diagnostics)?.1))
151 }
152 Expression::Cast { loc, expr, .. } => {
153 Ok((*loc, eval_const_number(expr, ns, diagnostics)?.1))
154 }
155 Expression::Not { loc, expr: n } => Ok((*loc, !eval_const_number(n, ns, diagnostics)?.1)),
156 Expression::BitwiseNot { loc, expr, .. } => {
157 Ok((*loc, !eval_const_number(expr, ns, diagnostics)?.1))
158 }
159 Expression::Negate { loc, expr, .. } => {
160 Ok((*loc, -eval_const_number(expr, ns, diagnostics)?.1))
161 }
162 Expression::ConstantVariable {
163 contract_no: Some(contract_no),
164 var_no,
165 ..
166 } => {
167 let var = &ns.contracts[*contract_no].variables[*var_no];
168
169 if let Some(init) = &var.initializer {
170 eval_const_number(init, ns, diagnostics)
171 } else {
172 Err(())
174 }
175 }
176 Expression::ConstantVariable {
177 contract_no: None,
178 var_no,
179 ..
180 } => {
181 let var = &ns.constants[*var_no];
182
183 if let Some(init) = &var.initializer {
184 eval_const_number(init, ns, diagnostics)
185 } else {
186 Err(())
188 }
189 }
190 _ => {
191 diagnostics.push(Diagnostic::error(
192 expr.loc(),
193 "expression not allowed in constant number expression".to_string(),
194 ));
195
196 Err(())
197 }
198 }
199}
200
201pub fn eval_const_rational(
203 expr: &Expression,
204 ns: &Namespace,
205) -> Result<(pt::Loc, BigRational), Diagnostic> {
206 match expr {
207 Expression::Add {
208 loc, left, right, ..
209 } => Ok((
210 *loc,
211 eval_const_rational(left, ns)?.1 + eval_const_rational(right, ns)?.1,
212 )),
213 Expression::Subtract {
214 loc, left, right, ..
215 } => Ok((
216 *loc,
217 eval_const_rational(left, ns)?.1 - eval_const_rational(right, ns)?.1,
218 )),
219 Expression::Multiply {
220 loc,
221 left: l,
222 right: r,
223 ..
224 } => Ok((
225 *loc,
226 eval_const_rational(l, ns)?.1 * eval_const_rational(r, ns)?.1,
227 )),
228 Expression::Divide {
229 loc, left, right, ..
230 } => {
231 let divisor = eval_const_rational(right, ns)?.1;
232
233 if divisor.is_zero() {
234 Err(Diagnostic::error(*loc, "divide by zero".to_string()))
235 } else {
236 Ok((*loc, eval_const_rational(left, ns)?.1 / divisor))
237 }
238 }
239 Expression::Modulo {
240 loc,
241 left: l,
242 right: r,
243 ..
244 } => {
245 let divisor = eval_const_rational(r, ns)?.1;
246
247 if divisor.is_zero() {
248 Err(Diagnostic::error(*loc, "divide by zero".to_string()))
249 } else {
250 Ok((*loc, eval_const_rational(l, ns)?.1 % divisor))
251 }
252 }
253 Expression::NumberLiteral { loc, value, .. } => {
254 Ok((*loc, BigRational::from_integer(value.clone())))
255 }
256 Expression::RationalNumberLiteral { loc, value, .. } => Ok((*loc, value.clone())),
257 Expression::Cast { loc, expr, .. } => Ok((*loc, eval_const_rational(expr, ns)?.1)),
258 Expression::Negate { loc, expr, .. } => Ok((*loc, -eval_const_rational(expr, ns)?.1)),
259 Expression::ConstantVariable {
260 contract_no: Some(contract_no),
261 var_no,
262 ..
263 } => {
264 let expr = ns.contracts[*contract_no].variables[*var_no]
265 .initializer
266 .as_ref()
267 .unwrap()
268 .clone();
269
270 eval_const_rational(&expr, ns)
271 }
272 Expression::ConstantVariable {
273 contract_no: None,
274 var_no,
275 ..
276 } => {
277 let expr = ns.constants[*var_no].initializer.as_ref().unwrap().clone();
278
279 eval_const_rational(&expr, ns)
280 }
281 _ => Err(Diagnostic::error(
282 expr.loc(),
283 "expression not allowed in constant rational number expression".to_string(),
284 )),
285 }
286}
287
288pub(super) fn check_term_for_constant_overflow(expr: &Expression, ns: &mut Namespace) -> bool {
291 match expr {
292 Expression::Add { .. }
293 | Expression::Subtract { .. }
294 | Expression::Multiply { .. }
295 | Expression::Divide { .. }
296 | Expression::Modulo { .. }
297 | Expression::Power { .. }
298 | Expression::ShiftLeft { .. }
299 | Expression::ShiftRight { .. }
300 | Expression::BitwiseAnd { .. }
301 | Expression::BitwiseOr { .. }
302 | Expression::BitwiseXor { .. }
303 | Expression::NumberLiteral { .. } => {
304 match eval_constants_in_expression(expr, &mut ns.diagnostics) {
305 (
306 Some(Expression::NumberLiteral {
307 loc,
308 ty,
309 value: result,
310 }),
311 _,
312 ) => {
313 if let Some(diagnostic) = overflow_diagnostic(&result, &ty, &loc) {
314 ns.diagnostics.push(diagnostic);
315 }
316
317 return false;
318 }
319 (None, false) => {
320 return false;
321 }
322 _ => {}
323 }
324 }
325 _ => {}
326 }
327
328 true
329}
330
331pub(crate) fn eval_constants_in_expression(
334 expr: &Expression,
335 diagnostics: &mut Diagnostics,
336) -> (Option<Expression>, bool) {
337 match expr {
338 Expression::Add {
339 loc,
340 ty,
341 unchecked: _,
342 left,
343 right,
344 } => {
345 let left = eval_constants_in_expression(left, diagnostics).0;
346 let right = eval_constants_in_expression(right, diagnostics).0;
347
348 if let (
349 Some(Expression::NumberLiteral { value: left, .. }),
350 Some(Expression::NumberLiteral { value: right, .. }),
351 ) = (left, right)
352 {
353 (
354 Some(Expression::NumberLiteral {
355 loc: *loc,
356 ty: ty.clone(),
357 value: left.add(right),
358 }),
359 true,
360 )
361 } else {
362 (None, true)
363 }
364 }
365 Expression::Subtract {
366 loc,
367 ty,
368 unchecked: _,
369 left,
370 right,
371 } => {
372 let left = eval_constants_in_expression(left, diagnostics).0;
373 let right = eval_constants_in_expression(right, diagnostics).0;
374
375 if let (
376 Some(Expression::NumberLiteral { value: left, .. }),
377 Some(Expression::NumberLiteral { value: right, .. }),
378 ) = (&left, &right)
379 {
380 (
381 Some(Expression::NumberLiteral {
382 loc: *loc,
383 ty: ty.clone(),
384 value: left.sub(right),
385 }),
386 true,
387 )
388 } else {
389 (None, true)
390 }
391 }
392
393 Expression::Multiply {
394 loc,
395 ty,
396 unchecked: _,
397 left,
398 right,
399 } => {
400 let left = eval_constants_in_expression(left, diagnostics).0;
401 let right = eval_constants_in_expression(right, diagnostics).0;
402
403 if let (
404 Some(Expression::NumberLiteral { value: left, .. }),
405 Some(Expression::NumberLiteral { value: right, .. }),
406 ) = (&left, &right)
407 {
408 (
409 Some(Expression::NumberLiteral {
410 loc: *loc,
411 ty: ty.clone(),
412 value: left.mul(right),
413 }),
414 true,
415 )
416 } else {
417 (None, true)
418 }
419 }
420 Expression::Divide {
421 loc,
422 ty,
423 left,
424 right,
425 } => {
426 let left = eval_constants_in_expression(left, diagnostics).0;
427 let right = eval_constants_in_expression(right, diagnostics).0;
428
429 if let (
430 Some(Expression::NumberLiteral { value: left, .. }),
431 Some(Expression::NumberLiteral { value: right, .. }),
432 ) = (&left, &right)
433 {
434 if right.is_zero() {
435 diagnostics.push(Diagnostic::error(*loc, "divide by zero".to_string()));
436 (None, false)
437 } else {
438 (
439 Some(Expression::NumberLiteral {
440 loc: *loc,
441 ty: ty.clone(),
442 value: left.div(right),
443 }),
444 true,
445 )
446 }
447 } else {
448 (None, true)
449 }
450 }
451
452 Expression::Modulo {
453 loc,
454 ty,
455 left,
456 right,
457 } => {
458 let left = eval_constants_in_expression(left, diagnostics).0;
459 let right = eval_constants_in_expression(right, diagnostics).0;
460
461 if let (
462 Some(Expression::NumberLiteral { value: left, .. }),
463 Some(Expression::NumberLiteral { value: right, .. }),
464 ) = (&left, &right)
465 {
466 if right.is_zero() {
467 diagnostics.push(Diagnostic::error(*loc, "divide by zero".to_string()));
468 (None, false)
469 } else {
470 (
471 Some(Expression::NumberLiteral {
472 loc: *loc,
473 ty: ty.clone(),
474 value: left % right,
475 }),
476 true,
477 )
478 }
479 } else {
480 (None, true)
481 }
482 }
483 Expression::Power {
484 loc,
485 ty,
486 unchecked: _,
487 base,
488 exp,
489 } => {
490 let base = eval_constants_in_expression(base, diagnostics).0;
491 let exp = eval_constants_in_expression(exp, diagnostics).0;
492
493 if let (
494 Some(Expression::NumberLiteral { value: left, .. }),
495 Some(Expression::NumberLiteral {
496 loc: right_loc,
497 value: right,
498 ..
499 }),
500 ) = (&base, &exp)
501 {
502 if overflow_diagnostic(right, &Type::Uint(16), right_loc).is_some() {
503 diagnostics.push(Diagnostic::error(
504 *right_loc,
505 format!("power by {right} is not possible"),
506 ));
507 (None, false)
508 } else {
509 (
510 Some(Expression::NumberLiteral {
511 loc: *loc,
512 ty: ty.clone(),
513 value: left.pow(right.to_u16().unwrap().into()),
514 }),
515 true,
516 )
517 }
518 } else {
519 (None, true)
520 }
521 }
522 Expression::ShiftLeft {
523 loc,
524 ty,
525 left,
526 right,
527 } => {
528 let left = eval_constants_in_expression(left, diagnostics).0;
529 let right = eval_constants_in_expression(right, diagnostics).0;
530
531 if let (
532 Some(Expression::NumberLiteral { value: left, .. }),
533 Some(Expression::NumberLiteral {
534 loc: right_loc,
535 value: right,
536 ..
537 }),
538 ) = (&left, &right)
539 {
540 if overflow_diagnostic(right, &Type::Uint(64), right_loc).is_some() {
541 diagnostics.push(Diagnostic::error(
542 *right_loc,
543 format!("left shift by {right} is not possible"),
544 ));
545 (None, false)
546 } else {
547 (
548 Some(Expression::NumberLiteral {
549 loc: *loc,
550 ty: ty.clone(),
551 value: left.shl(right.to_u64().unwrap()),
552 }),
553 true,
554 )
555 }
556 } else {
557 (None, true)
558 }
559 }
560
561 Expression::ShiftRight {
562 loc,
563 ty,
564 left,
565 right,
566 sign: _,
567 } => {
568 let left = eval_constants_in_expression(left, diagnostics).0;
569 let right = eval_constants_in_expression(right, diagnostics).0;
570
571 if let (
572 Some(Expression::NumberLiteral { value: left, .. }),
573 Some(Expression::NumberLiteral {
574 loc: right_loc,
575 value: right,
576 ..
577 }),
578 ) = (&left, &right)
579 {
580 if overflow_diagnostic(right, &Type::Uint(64), right_loc).is_some() {
581 diagnostics.push(Diagnostic::error(
582 *right_loc,
583 format!("right shift by {right} is not possible"),
584 ));
585 (None, false)
586 } else {
587 (
588 Some(Expression::NumberLiteral {
589 loc: *loc,
590 ty: ty.clone(),
591 value: left.shr(right.to_u64().unwrap()),
592 }),
593 true,
594 )
595 }
596 } else {
597 (None, true)
598 }
599 }
600 Expression::BitwiseAnd {
601 loc,
602 ty,
603 left,
604 right,
605 } => {
606 let left = eval_constants_in_expression(left, diagnostics).0;
607 let right = eval_constants_in_expression(right, diagnostics).0;
608
609 if let (
610 Some(Expression::NumberLiteral { value: left, .. }),
611 Some(Expression::NumberLiteral { value: right, .. }),
612 ) = (&left, &right)
613 {
614 (
615 Some(Expression::NumberLiteral {
616 loc: *loc,
617 ty: ty.clone(),
618 value: left.bitand(right),
619 }),
620 true,
621 )
622 } else {
623 (None, true)
624 }
625 }
626 Expression::BitwiseOr {
627 loc,
628 ty,
629 left,
630 right,
631 } => {
632 let left = eval_constants_in_expression(left, diagnostics).0;
633 let right = eval_constants_in_expression(right, diagnostics).0;
634
635 if let (
636 Some(Expression::NumberLiteral { value: left, .. }),
637 Some(Expression::NumberLiteral { value: right, .. }),
638 ) = (&left, &right)
639 {
640 (
641 Some(Expression::NumberLiteral {
642 loc: *loc,
643 ty: ty.clone(),
644 value: left.bitor(right),
645 }),
646 true,
647 )
648 } else {
649 (None, true)
650 }
651 }
652 Expression::BitwiseXor {
653 loc,
654 ty,
655 left,
656 right,
657 } => {
658 let left = eval_constants_in_expression(left, diagnostics).0;
659 let right = eval_constants_in_expression(right, diagnostics).0;
660
661 if let (
662 Some(Expression::NumberLiteral { value: left, .. }),
663 Some(Expression::NumberLiteral { value: right, .. }),
664 ) = (&left, &right)
665 {
666 (
667 Some(Expression::NumberLiteral {
668 loc: *loc,
669 ty: ty.clone(),
670 value: left.bitxor(right),
671 }),
672 true,
673 )
674 } else {
675 (None, true)
676 }
677 }
678 Expression::ZeroExt { loc, to, expr } => {
679 let expr = eval_constants_in_expression(expr, diagnostics).0;
680 if let Some(Expression::NumberLiteral { value, .. }) = expr {
681 (
682 Some(Expression::NumberLiteral {
683 loc: *loc,
684 ty: to.clone(),
685 value,
686 }),
687 true,
688 )
689 } else {
690 (None, true)
691 }
692 }
693 Expression::SignExt { loc, to, expr } => {
694 let expr = eval_constants_in_expression(expr, diagnostics).0;
695 if let Some(Expression::NumberLiteral { value, .. }) = expr {
696 (
697 Some(Expression::NumberLiteral {
698 loc: *loc,
699 ty: to.clone(),
700 value,
701 }),
702 true,
703 )
704 } else {
705 (None, true)
706 }
707 }
708 Expression::NumberLiteral { .. } => (Some(expr.clone()), true),
709 _ => (None, true),
710 }
711}
712
713pub(crate) fn overflow_diagnostic(result: &BigInt, ty: &Type, loc: &Loc) -> Option<Diagnostic> {
715 if result.bits() > 1024 {
716 if let Type::Uint(bits) = ty {
721 if let Sign::Minus = result.sign() {
723 return Some(Diagnostic::error(
724 *loc,
725 format!( "large negative value does not fit into type uint{}. Cannot implicitly convert signed literal to unsigned type.",
726 ty.get_type_size()),
727 ));
728 }
729
730 if result.bits() > *bits as u64 {
732 return Some(Diagnostic::error(
733 *loc,
734 format!(
735 "value is too large to fit into type uint{}",
736 ty.get_type_size(),
737 ),
738 ));
739 }
740 }
741
742 if let Type::Int(bits) = ty {
743 if result.to_signed_bytes_be().len() * 8 > (*bits as usize) {
745 return Some(Diagnostic::error(
746 *loc,
747 format!(
748 "value is too large to fit into type int{}",
749 ty.get_type_size(),
750 ),
751 ));
752 }
753 }
754 } else {
755 if let Type::Uint(bits) = ty {
756 if let Sign::Minus = result.sign() {
758 return Some(Diagnostic::error(
759 *loc,
760 format!( "negative value {} does not fit into type uint{}. Cannot implicitly convert signed literal to unsigned type.",result,ty.get_type_size()),
761 ));
762 }
763
764 if result.bits() > *bits as u64 {
766 return Some(Diagnostic::error(
767 *loc,
768 format!(
769 "value {} does not fit into type uint{}.",
770 result,
771 ty.get_type_size(),
772 ),
773 ));
774 }
775 }
776
777 if let Type::Int(bits) = ty {
778 if result.to_signed_bytes_be().len() * 8 > (*bits as usize) {
780 return Some(Diagnostic::error(
781 *loc,
782 format!(
783 "value {} does not fit into type int{}.",
784 result,
785 ty.get_type_size(),
786 ),
787 ));
788 }
789 }
790 }
791 None
792}