pass mutable reference to circuit variable when 'mut self' keyword is present

This commit is contained in:
collin 2020-12-01 10:12:50 -05:00
parent 74f7749462
commit 82e13edbbe
9 changed files with 69 additions and 13 deletions

View File

@ -68,6 +68,14 @@ impl Function {
self.input.iter().find(|param| param.is_self()).is_some()
}
///
/// Returns `true` if the function has input `mut self`.
/// Returns `false` otherwise.
///
pub fn contains_mut_self(&self) -> bool {
self.input.iter().find(|param| param.is_mut_self()).is_some()
}
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "function {}", self.identifier)?;

View File

@ -56,6 +56,19 @@ impl FunctionInput {
}
}
///
/// Returns `true` if the function input is the `mut self` keyword.
/// Returns `false` otherwise.
///
pub fn is_mut_self(&self) -> bool {
match self {
FunctionInput::InputKeyword(_) => false,
FunctionInput::SelfKeyword(_) => false,
FunctionInput::MutSelfKeyword(_) => true,
FunctionInput::Variable(_) => false,
}
}
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FunctionInput::InputKeyword(keyword) => write!(f, "{}", keyword),

View File

@ -46,22 +46,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
for (input_model, input_expression) in function.input.iter().zip(input.into_iter()) {
let (name, value) = match input_model {
FunctionInput::InputKeyword(keyword) => {
let input_value =
let value =
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
(keyword.to_string(), input_value)
(keyword.to_string(), value)
}
FunctionInput::SelfKeyword(keyword) => {
let input_value =
let value =
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
(keyword.to_string(), input_value)
(keyword.to_string(), value)
}
FunctionInput::MutSelfKeyword(keyword) => {
let input_value =
let value =
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
(keyword.to_string(), input_value)
(keyword.to_string(), value)
}
FunctionInput::Variable(input_model) => {
// First evaluate input expression
@ -87,6 +87,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
self.store(input_program_identifier, value);
}
let mut_self = function.contains_mut_self();
// Evaluate every statement in the function and save all potential results
let mut results = vec![];
@ -99,6 +101,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
statement.clone(),
function.output.clone(),
declared_circuit_reference,
mut_self,
)?;
results.append(&mut result);

View File

@ -42,6 +42,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
file_scope: &str,
function_scope: &str,
declared_circuit_reference: &str,
mut_self: bool,
indicator: Option<Boolean>,
assignee: Assignee,
expression: Expression,
@ -88,7 +89,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
AssigneeAccess::Member(identifier) => {
// Mutate a circuit variable using the self keyword.
if assignee.identifier.is_self() {
if assignee.identifier.is_self() && mut_self {
let self_circuit_variable_name = new_scope(&assignee.identifier.name, &identifier.name);
let self_variable_name = new_scope(file_scope, &self_circuit_variable_name);
let value = self.mutate_circuit_variable(

View File

@ -89,12 +89,31 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(selected_value)
}
_ => {
// Throw an error if we try to mutate an immutable circuit variable
Err(StatementError::immutable_circuit_variable(
variable_name.name,
value => {
// Check that the new value type == old value type
new_value.resolve_type(Some(value.to_type(span)?), span)?;
// Conditionally select the value if this branch is executed.
let mut selected_value = ConstrainedValue::conditionally_select(
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
&condition,
&new_value,
&member.1,
)
.map_err(|_| {
StatementError::select_fail(
new_value.to_string(),
member.1.to_string(),
span.to_owned(),
))
)
})?;
// Make sure the new value is still mutable
selected_value = ConstrainedValue::Mutable(Box::new(selected_value));
member.1 = selected_value.to_owned();
Ok(selected_value)
}
},
None => {

View File

@ -33,6 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator: Option<Boolean>,
statements: Vec<Statement>,
return_type: Option<Type>,
mut_self: bool,
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
let mut results = Vec::with_capacity(statements.len());
// Evaluate statements. Only allow a single return argument to be returned.
@ -45,6 +46,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
statement,
return_type.clone(),
"",
mut_self,
)?;
results.append(&mut value);

View File

@ -52,6 +52,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator: Option<Boolean>,
statement: ConditionalStatement,
return_type: Option<Type>,
mut_self: bool,
span: &Span,
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
let statement_string = statement.to_string();
@ -95,6 +96,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Some(branch_1_indicator),
statement.statements,
return_type.clone(),
mut_self,
)?;
results.append(&mut branch_1_result);
@ -123,6 +125,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Some(branch_2_indicator),
*nested,
return_type,
mut_self,
span,
)?,
ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch(
@ -132,6 +135,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Some(branch_2_indicator),
statements,
return_type,
mut_self,
)?,
},
None => vec![],

View File

@ -48,6 +48,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
stop: Expression,
statements: Vec<Statement>,
return_type: Option<Type>,
mut_self: bool,
span: &Span,
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
let mut results = vec![];
@ -74,6 +75,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator,
statements.clone(),
return_type.clone(),
mut_self,
)?;
results.append(&mut result);

View File

@ -45,6 +45,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
statement: Statement,
return_type: Option<Type>,
declared_circuit_reference: &str,
mut_self: bool,
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
let mut results = vec![];
@ -74,6 +75,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
file_scope,
function_scope,
declared_circuit_reference,
mut_self,
indicator,
variable,
expression,
@ -88,6 +90,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator,
statement,
return_type,
mut_self,
&span,
)?;
@ -104,6 +107,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
start_stop.1,
statements,
return_type,
mut_self,
&span,
)?;