fix boolean namespaces and errors

This commit is contained in:
collin 2020-06-20 18:43:45 -07:00
parent 03c6af2d46
commit d1dfdcb878
6 changed files with 99 additions and 56 deletions

View File

@ -5,7 +5,7 @@ use crate::{
errors::BooleanError,
GroupType,
};
use leo_types::InputValue;
use leo_types::{InputValue, Span};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -22,6 +22,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
name: String,
input_value: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
// Check that the input value is the correct type
let bool_value = match input_value {
@ -29,21 +30,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
if let InputValue::Boolean(bool) = input {
Some(bool)
} else {
return Err(BooleanError::SynthesisError(SynthesisError::AssignmentMissing));
return Err(BooleanError::invalid_boolean(name, span));
}
}
None => None,
};
let number = Boolean::alloc(cs.ns(|| name), || bool_value.ok_or(SynthesisError::AssignmentMissing))?;
let boolean_name = format!("{}: bool", name);
let boolean_name_unique = format!("`{}` {}:{}", boolean_name, span.line, span.start);
let number = Boolean::alloc(cs.ns(|| boolean_name_unique), || {
bool_value.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| BooleanError::missing_boolean(boolean_name, span))?;
Ok(ConstrainedValue::Boolean(number))
}
pub(crate) fn evaluate_not(value: ConstrainedValue<F, G>) -> Result<ConstrainedValue<F, G>, BooleanError> {
pub(crate) fn evaluate_not(
value: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match value {
ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())),
value => Err(BooleanError::CannotEvaluate(format!("!{}", value))),
value => Err(BooleanError::cannot_evaluate(format!("!{}", value), span)),
}
}
@ -52,15 +61,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match (left, right) {
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => {
Ok(ConstrainedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool)?))
Ok(ConstrainedValue::Boolean(
Boolean::or(cs, &left_bool, &right_bool)
.map_err(|e| BooleanError::cannot_enforce(format!("||"), e, span))?,
))
}
(left_value, right_value) => Err(BooleanError::CannotEnforce(format!(
"{} || {}",
left_value, right_value
))),
(left_value, right_value) => Err(BooleanError::cannot_evaluate(
format!("{} || {}", left_value, right_value),
span,
)),
}
}
@ -69,15 +82,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match (left, right) {
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => {
Ok(ConstrainedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool)?))
Ok(ConstrainedValue::Boolean(
Boolean::and(cs, &left_bool, &right_bool)
.map_err(|e| BooleanError::cannot_enforce(format!("&&"), e, span))?,
))
}
(left_value, right_value) => Err(BooleanError::CannotEnforce(format!(
"{} && {}",
left_value, right_value
))),
(left_value, right_value) => Err(BooleanError::cannot_evaluate(
format!("{} && {}", left_value, right_value),
span,
)),
}
}
}

View File

@ -939,13 +939,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
// Boolean operations
Expression::Not(expression) => Ok(Self::evaluate_not(self.enforce_expression(
cs,
file_scope,
function_scope,
expected_types,
*expression,
)?)?),
Expression::Not(expression, span) => Ok(Self::evaluate_not(
self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?,
span,
)?),
Expression::Or(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
@ -957,7 +954,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.clone(),
)?;
Ok(self.enforce_or(cs, resolved_left, resolved_right)?)
Ok(self.enforce_or(cs, resolved_left, resolved_right, span)?)
}
Expression::And(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
@ -970,7 +967,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.clone(),
)?;
Ok(self.enforce_and(cs, resolved_left, resolved_right)?)
Ok(self.enforce_and(cs, resolved_left, resolved_right, span)?)
}
Expression::Eq(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(

View File

@ -173,7 +173,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
)?)),
Type::Field => Ok(field_from_input(cs, name, input_value, span)?),
Type::Group => Ok(group_from_input(cs, name, input_value, span)?),
Type::Boolean => Ok(self.bool_from_input(cs, name, input_value)?),
Type::Boolean => Ok(self.bool_from_input(cs, name, input_value, span)?),
Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_value, span),
_ => unimplemented!("main function input not implemented for type"),
}

View File

@ -1,9 +1,14 @@
use leo_types::{Error as FormattedError, Span};
use snarkos_errors::gadgets::SynthesisError;
use std::str::ParseBoolError;
#[derive(Debug, Error)]
pub enum BooleanError {
#[error("{}", _0)]
Error(#[from] FormattedError),
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),
@ -16,3 +21,36 @@ pub enum BooleanError {
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
}
impl BooleanError {
fn new_from_span(message: String, span: Span) -> Self {
BooleanError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
let message = format!(
"the boolean operation `{}` failed due to the synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn cannot_evaluate(operation: String, span: Span) -> Self {
let message = format!("no implementation found for `{}`", operation);
Self::new_from_span(message, span)
}
pub fn invalid_boolean(actual: String, span: Span) -> Self {
let message = format!("expected boolean input type, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn missing_boolean(expected: String, span: Span) -> Self {
let message = format!("expected boolean input `{}` not found", expected);
Self::new_from_span(message, span)
}
}

View File

@ -23,35 +23,19 @@ pub fn output_false(program: EdwardsTestCompiler) {
output_expected_boolean(program, false)
}
fn fail_evaluate(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::CannotEvaluate(_string)),
))) => {}
error => panic!("Expected evaluate error, got {}", error),
}
}
fn fail_enforce(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::CannotEnforce(_string)),
))) => {}
error => panic!("Expected evaluate error, got {}", error),
}
}
fn fail_boolean(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::SynthesisError(_))) => {}
error => panic!("Expected invalid boolean error, got {}", error),
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::Error(_))) => {}
error => panic!("Expected boolean error, got {}", error),
}
}
fn fail_synthesis(program: EdwardsTestCompiler) {
fn fail_boolean_statement(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::SynthesisError(_string))) => {}
error => panic!("Expected synthesis error, got {}", error),
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::Error(_)),
))) => {}
_ => panic!("Expected boolean error, got {}"),
}
}
@ -88,7 +72,7 @@ fn test_input_bool_none() {
program.set_inputs(vec![None]);
fail_synthesis(program);
fail_boolean(program);
}
// Boolean not !
@ -114,7 +98,7 @@ fn test_not_u32() {
let bytes = include_bytes!("not_u32.leo");
let program = parse_program(bytes).unwrap();
fail_evaluate(program);
fail_boolean_statement(program)
}
// Boolean or ||
@ -148,7 +132,7 @@ fn test_true_or_u32() {
let bytes = include_bytes!("true_or_u32.leo");
let program = parse_program(bytes).unwrap();
fail_enforce(program);
fail_boolean_statement(program);
}
// Boolean and &&
@ -182,7 +166,7 @@ fn test_true_and_u32() {
let bytes = include_bytes!("true_and_u32.leo");
let program = parse_program(bytes).unwrap();
fail_enforce(program);
fail_boolean_statement(program);
}
// All

View File

@ -41,7 +41,7 @@ pub enum Expression {
Pow(Box<Expression>, Box<Expression>, Span),
// Boolean operations
Not(Box<Expression>),
Not(Box<Expression>, Span),
Or(Box<Expression>, Box<Expression>, Span),
And(Box<Expression>, Box<Expression>, Span),
Eq(Box<Expression>, Box<Expression>, Span),
@ -78,6 +78,7 @@ impl Expression {
Expression::Div(_, _, old_span) => *old_span = new_span.clone(),
Expression::Pow(_, _, old_span) => *old_span = new_span.clone(),
Expression::Not(_, old_span) => *old_span = new_span.clone(),
Expression::Or(_, _, old_span) => *old_span = new_span.clone(),
Expression::And(_, _, old_span) => *old_span = new_span.clone(),
Expression::Eq(_, _, old_span) => *old_span = new_span.clone(),
@ -135,7 +136,7 @@ impl<'ast> fmt::Display for Expression {
Expression::Pow(ref left, ref right, ref _span) => write!(f, "{} ** {}", left, right),
// Boolean operations
Expression::Not(ref expression) => write!(f, "!{}", expression),
Expression::Not(ref expression, ref _span) => write!(f, "!{}", expression),
Expression::Or(ref lhs, ref rhs, ref _span) => write!(f, "{} || {}", lhs, rhs),
Expression::And(ref lhs, ref rhs, ref _span) => write!(f, "{} && {}", lhs, rhs),
Expression::Eq(ref lhs, ref rhs, ref _span) => write!(f, "{} == {}", lhs, rhs),
@ -312,7 +313,10 @@ impl<'ast> From<BinaryExpression<'ast>> for Expression {
Box::new(Expression::from(*expression.right)),
Span::from(expression.span),
),
BinaryOperation::Ne => Expression::Not(Box::new(Expression::from(expression))),
BinaryOperation::Ne => Expression::Not(
Box::new(Expression::from(expression.clone())),
Span::from(expression.span),
),
BinaryOperation::Ge => Expression::Ge(
Box::new(Expression::from(*expression.left)),
Box::new(Expression::from(*expression.right)),
@ -410,7 +414,10 @@ impl<'ast> From<Value<'ast>> for Expression {
impl<'ast> From<NotExpression<'ast>> for Expression {
fn from(expression: NotExpression<'ast>) -> Self {
Expression::Not(Box::new(Expression::from(*expression.expression)))
Expression::Not(
Box::new(Expression::from(*expression.expression)),
Span::from(expression.span),
)
}
}