Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return an error instead of panicking (#419) #672

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions crates/noirc_evaluator/src/ssa/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ impl Binary {
}
assert_eq!(l_type, r_type);
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, l_type, u128::add, Add::add));
return wrapping(lhs, rhs, l_type, u128::add, Add::add);
}
//if only one is const, we could try to do constant propagation but this will be handled by the arithmetization step anyways
//so it is probably not worth it.
Expand All @@ -760,7 +760,7 @@ impl Binary {
}
//constant folding
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::wrapping_sub, Sub::sub));
return wrapping(lhs, rhs, res_type, u128::wrapping_sub, Sub::sub);
}
}
BinaryOp::Mul | BinaryOp::SafeMul => {
Expand All @@ -772,7 +772,7 @@ impl Binary {
} else if r_is_zero || l_is_one {
return Ok(r_eval);
} else if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::mul, Mul::mul));
return wrapping(lhs, rhs, res_type, u128::mul, Mul::mul);
}
//if only one is const, we could try to do constant propagation but this will be handled by the arithmetization step anyways
//so it is probably not worth it.
Expand Down Expand Up @@ -893,7 +893,7 @@ impl Binary {
} else if r_is_zero {
return Ok(r_eval);
} else if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::bitand, field_op_not_allowed));
return wrapping_no_field(lhs, rhs, res_type, u128::bitand, "and");
}
//TODO if boolean and not zero, also checks this is correct for field elements
}
Expand All @@ -904,7 +904,7 @@ impl Binary {
} else if r_is_zero {
return Ok(l_eval);
} else if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::bitor, field_op_not_allowed));
return wrapping_no_field(lhs, rhs, res_type, u128::bitor, "or");
}
//TODO if boolean and not zero, also checks this is correct for field elements
}
Expand All @@ -916,7 +916,7 @@ impl Binary {
} else if r_is_zero {
return Ok(l_eval);
} else if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::bitxor, field_op_not_allowed));
return wrapping_no_field(lhs, rhs, res_type, u128::bitxor, "xor");
}
//TODO handle case when lhs is one (or rhs is one) by generating 'not rhs' instruction (or 'not lhs' instruction)
}
Expand All @@ -928,7 +928,7 @@ impl Binary {
return Ok(l_eval);
}
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::shl, field_op_not_allowed));
return wrapping_no_field(lhs, rhs, res_type, u128::shl, "shl");
}
}
BinaryOp::Shr => {
Expand All @@ -939,7 +939,7 @@ impl Binary {
return Ok(l_eval);
}
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
return Ok(wrapping(lhs, rhs, res_type, u128::shr, field_op_not_allowed));
return wrapping_no_field(lhs, rhs, res_type, u128::shr, "shr");
}
}
BinaryOp::Assign => (),
Expand Down Expand Up @@ -1016,21 +1016,42 @@ fn wrapping(
res_type: ObjectType,
u128_op: impl FnOnce(u128, u128) -> u128,
field_op: impl FnOnce(FieldElement, FieldElement) -> FieldElement,
) -> NodeEval {
) -> Result<NodeEval, RuntimeError> {
if res_type != ObjectType::NativeField {
let type_modulo = 1_u128 << res_type.bits();
let lhs = lhs.to_u128() % type_modulo;
let rhs = rhs.to_u128() % type_modulo;
let mut x = u128_op(lhs, rhs);
x %= type_modulo;
NodeEval::from_u128(x, res_type)
Ok(NodeEval::from_u128(x, res_type))
} else {
NodeEval::Const(field_op(lhs, rhs), res_type)
Ok(NodeEval::Const(field_op(lhs, rhs), res_type))
}
}

fn field_op_not_allowed(_lhs: FieldElement, _rhs: FieldElement) -> FieldElement {
unreachable!("operation not allowed for FieldElement");
/// Perform the given numeric operation modulto the res_type bit size and returns an error is res_type is a NativeField
fn wrapping_no_field(
lhs: FieldElement,
rhs: FieldElement,
res_type: ObjectType,
u128_op: impl FnOnce(u128, u128) -> u128,
op_name: &str,
) -> Result<NodeEval, RuntimeError> {
if res_type != ObjectType::NativeField {
let type_modulo = 1_u128 << res_type.bits();
let lhs = lhs.to_u128() % type_modulo;
let rhs = rhs.to_u128() % type_modulo;
let mut x = u128_op(lhs, rhs);
x %= type_modulo;
Ok(NodeEval::from_u128(x, res_type))
} else {
Err(RuntimeErrorKind::UnsupportedOp {
op: op_name.to_string(),
first_type: "FieldElement".to_string(),
second_type: "FieldElement".to_string(),
}
.into())
}
}

impl Operation {
Expand Down