mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-28 01:01:53 +03:00
Merge pull request #348 from AleoHQ/feature/mutable-self-circuit-values
Feature/mutable self circuit values
This commit is contained in:
commit
89dbe6bcf5
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{access::AssigneeAccess, ast::Rule, common::Identifier, SpanDef};
|
||||
use crate::{access::AssigneeAccess, ast::Rule, common::KeywordOrIdentifier, SpanDef};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
@ -24,7 +24,7 @@ use std::fmt;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::assignee))]
|
||||
pub struct Assignee<'ast> {
|
||||
pub identifier: Identifier<'ast>,
|
||||
pub name: KeywordOrIdentifier<'ast>,
|
||||
pub accesses: Vec<AssigneeAccess<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
@ -33,7 +33,7 @@ pub struct Assignee<'ast> {
|
||||
|
||||
impl<'ast> fmt::Display for Assignee<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.identifier)?;
|
||||
write!(f, "{}", self.name)?;
|
||||
for (i, access) in self.accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < self.accesses.len() - 1 {
|
||||
|
43
ast/src/common/keyword_or_identifier.rs
Normal file
43
ast/src/common/keyword_or_identifier.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2019-2020 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
ast::Rule,
|
||||
common::{Identifier, SelfKeyword},
|
||||
functions::InputKeyword,
|
||||
};
|
||||
|
||||
use pest_ast::FromPest;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::keyword_or_identifier))]
|
||||
pub enum KeywordOrIdentifier<'ast> {
|
||||
SelfKeyword(SelfKeyword<'ast>),
|
||||
Input(InputKeyword<'ast>),
|
||||
Identifier(Identifier<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for KeywordOrIdentifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
KeywordOrIdentifier::SelfKeyword(self_keyword) => write!(f, "{}", self_keyword),
|
||||
KeywordOrIdentifier::Input(input_keyword) => write!(f, "{}", input_keyword),
|
||||
KeywordOrIdentifier::Identifier(identifier) => write!(f, "{}", identifier),
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,9 @@ pub use eoi::*;
|
||||
pub mod identifier;
|
||||
pub use identifier::*;
|
||||
|
||||
pub mod keyword_or_identifier;
|
||||
pub use keyword_or_identifier::*;
|
||||
|
||||
pub mod line_end;
|
||||
pub use line_end::*;
|
||||
|
||||
|
@ -22,6 +22,7 @@ use crate::{
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::self_keyword))]
|
||||
@ -32,3 +33,9 @@ pub struct SelfKeyword<'ast> {
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for SelfKeyword<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.keyword)
|
||||
}
|
||||
}
|
||||
|
@ -14,13 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
access::Access,
|
||||
ast::Rule,
|
||||
common::{Identifier, SelfKeyword},
|
||||
functions::InputKeyword,
|
||||
SpanDef,
|
||||
};
|
||||
use crate::{access::Access, ast::Rule, common::KeywordOrIdentifier, SpanDef};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
@ -35,11 +29,3 @@ pub struct PostfixExpression<'ast> {
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::keyword_or_identifier))]
|
||||
pub enum KeywordOrIdentifier<'ast> {
|
||||
SelfKeyword(SelfKeyword<'ast>),
|
||||
Input(InputKeyword<'ast>),
|
||||
Identifier(Identifier<'ast>),
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use crate::{
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::input_keyword))]
|
||||
@ -32,3 +33,9 @@ pub struct InputKeyword<'ast> {
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for InputKeyword<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.keyword)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/// Common
|
||||
|
||||
// Declared in common/assignee.rs
|
||||
assignee = { identifier ~ access_assignee* }
|
||||
assignee = { keyword_or_identifier ~ access_assignee* }
|
||||
|
||||
// Declared in files/file.rs
|
||||
file = { SOI ~ NEWLINE* ~ definition* ~ NEWLINE* ~ EOI }
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
//! Enforce a function call expression in a compiled Leo program.
|
||||
|
||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use crate::{errors::ExpressionError, new_scope, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_typed::{Expression, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
@ -35,13 +35,32 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
arguments: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let function_value = self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
*function.clone(),
|
||||
)?;
|
||||
let (declared_circuit_reference, function_value) = match *function.clone() {
|
||||
Expression::CircuitMemberAccess(circuit_identifier, circuit_member, span) => {
|
||||
// Call a circuit function that can mutate self.
|
||||
|
||||
// Save a reference to the circuit we are mutating.
|
||||
let circuit_id_string = format!("{}", circuit_identifier);
|
||||
let declared_circuit_reference = new_scope(function_scope.clone(), circuit_id_string);
|
||||
|
||||
(
|
||||
declared_circuit_reference,
|
||||
self.enforce_circuit_access(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
circuit_identifier,
|
||||
circuit_member,
|
||||
span,
|
||||
)?,
|
||||
)
|
||||
}
|
||||
function => (
|
||||
function_scope.clone(),
|
||||
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_type, function)?,
|
||||
),
|
||||
};
|
||||
|
||||
let (outer_scope, function_call) = function_value.extract_function(file_scope.clone(), span.clone())?;
|
||||
|
||||
@ -58,6 +77,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
function_scope,
|
||||
function_call,
|
||||
arguments,
|
||||
declared_circuit_reference,
|
||||
)
|
||||
.map_err(|error| ExpressionError::from(Box::new(error)))
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
caller_scope: String,
|
||||
function: Function,
|
||||
input: Vec<Expression>,
|
||||
declared_circuit_reference: String,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
let function_name = new_scope(scope.clone(), function.get_name());
|
||||
|
||||
@ -103,6 +104,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
None,
|
||||
statement.clone(),
|
||||
function.returns.clone(),
|
||||
declared_circuit_reference.clone(),
|
||||
)?;
|
||||
|
||||
results.append(&mut result);
|
||||
|
@ -77,7 +77,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
let span = function.span.clone();
|
||||
let result_value = self.enforce_function(cs, scope, function_name, function, input_variables)?;
|
||||
let result_value = self.enforce_function(cs, scope, function_name, function, input_variables, "".to_owned())?;
|
||||
let output_bytes = OutputBytes::new_from_constrained_value(registers, result_value, span)?;
|
||||
|
||||
Ok(output_bytes)
|
||||
|
@ -19,6 +19,7 @@
|
||||
use crate::{
|
||||
assignee::resolve_assignee,
|
||||
errors::StatementError,
|
||||
new_scope,
|
||||
program::ConstrainedProgram,
|
||||
value::ConstrainedValue,
|
||||
GroupType,
|
||||
@ -39,6 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
declared_circuit_reference: String,
|
||||
indicator: Option<Boolean>,
|
||||
assignee: Assignee,
|
||||
expression: Expression,
|
||||
@ -79,8 +81,34 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
span,
|
||||
),
|
||||
Assignee::Tuple(_tuple, index) => self.assign_tuple(cs, indicator, variable_name, index, new_value, span),
|
||||
Assignee::CircuitField(_assignee, object_name) => {
|
||||
self.mutute_circuit_variable(cs, indicator, variable_name, object_name, new_value, span)
|
||||
Assignee::CircuitField(assignee, circuit_variable) => {
|
||||
// Mutate a circuit variable using the self keyword.
|
||||
if let Assignee::Identifier(circuit_name) = *assignee {
|
||||
if circuit_name.is_self() {
|
||||
let self_circuit_variable_name = new_scope(circuit_name.name, circuit_variable.name.clone());
|
||||
let self_variable_name = new_scope(file_scope, self_circuit_variable_name);
|
||||
let value = self.mutate_circuit_variable(
|
||||
cs,
|
||||
indicator,
|
||||
declared_circuit_reference,
|
||||
circuit_variable,
|
||||
new_value,
|
||||
span,
|
||||
)?;
|
||||
|
||||
self.store(self_variable_name, value);
|
||||
} else {
|
||||
let _value = self.mutate_circuit_variable(
|
||||
cs,
|
||||
indicator,
|
||||
variable_name,
|
||||
circuit_variable,
|
||||
new_value,
|
||||
span,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn mutute_circuit_variable<CS: ConstraintSystem<F>>(
|
||||
pub fn mutate_circuit_variable<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
indicator: Option<Boolean>,
|
||||
@ -36,7 +36,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
variable_name: Identifier,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
|
||||
// Get the mutable circuit by name
|
||||
@ -48,19 +48,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
match matched_variable {
|
||||
Some(member) => match &member.1 {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
return Err(StatementError::immutable_circuit_function(
|
||||
// Throw an error if we try to mutate a circuit function
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
function.identifier.to_string(),
|
||||
span,
|
||||
));
|
||||
))
|
||||
}
|
||||
ConstrainedValue::Static(_value) => {
|
||||
return Err(StatementError::immutable_circuit_function("static".into(), span));
|
||||
ConstrainedValue::Static(_circuit_function) => {
|
||||
// Throw an error if we try to mutate a static circuit function
|
||||
Err(StatementError::immutable_circuit_function("static".into(), span))
|
||||
}
|
||||
ConstrainedValue::Mutable(value) => {
|
||||
// Mutate the circuit variable's value in place
|
||||
|
||||
// Check that the new value type == old value type
|
||||
new_value.resolve_type(Some(value.to_type(span.clone())?), span.clone())?;
|
||||
|
||||
// Conditionally select the value if this branch is executed.
|
||||
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
let mut selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| name_unique),
|
||||
&condition,
|
||||
&new_value,
|
||||
@ -70,23 +76,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
StatementError::select_fail(new_value.to_string(), member.1.to_string(), span)
|
||||
})?;
|
||||
|
||||
// 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.to_owned())
|
||||
}
|
||||
_ => {
|
||||
return Err(StatementError::immutable_circuit_variable(variable_name.name, span));
|
||||
// Throw an error if we try to mutate an immutable circuit variable
|
||||
Err(StatementError::immutable_circuit_variable(variable_name.name, span))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(StatementError::undefined_circuit_variable(
|
||||
// Throw an error if the circuit variable does not exist in the circuit
|
||||
Err(StatementError::undefined_circuit_variable(
|
||||
variable_name.to_string(),
|
||||
span,
|
||||
));
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err(StatementError::undefined_circuit(variable_name.to_string(), span)),
|
||||
// Throw an error if the circuit definition does not exist in the file
|
||||
_ => Err(StatementError::undefined_circuit(variable_name.to_string(), span)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
indicator.clone(),
|
||||
statement.clone(),
|
||||
return_type.clone(),
|
||||
"".to_owned(),
|
||||
)?;
|
||||
|
||||
results.append(&mut value);
|
||||
|
@ -38,6 +38,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
indicator: Option<Boolean>,
|
||||
statement: Statement,
|
||||
return_type: Option<Type>,
|
||||
declared_circuit_reference: String,
|
||||
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
|
||||
let mut results = vec![];
|
||||
|
||||
@ -62,7 +63,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
)?;
|
||||
}
|
||||
Statement::Assign(variable, expression, span) => {
|
||||
self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression, span)?;
|
||||
self.enforce_assign_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
declared_circuit_reference,
|
||||
indicator,
|
||||
variable,
|
||||
expression,
|
||||
span,
|
||||
)?;
|
||||
}
|
||||
Statement::Conditional(statement, span) => {
|
||||
let mut result = self.enforce_conditional_statement(
|
||||
|
@ -134,6 +134,71 @@ fn test_member_static_function_undefined() {
|
||||
expect_fail(program)
|
||||
}
|
||||
|
||||
// Mutability
|
||||
#[test]
|
||||
fn test_mutate_function_fail() {
|
||||
let bytes = include_bytes!("mut_function_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_self_variable() {
|
||||
let bytes = include_bytes!("mut_self_variable.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_self_variable_fail() {
|
||||
let bytes = include_bytes!("mut_self_variable_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_self_function_fail() {
|
||||
let bytes = include_bytes!("mut_self_function_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_self_static_function_fail() {
|
||||
let bytes = include_bytes!("mut_self_static_function_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_static_function_fail() {
|
||||
let bytes = include_bytes!("mut_static_function_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_variable() {
|
||||
let bytes = include_bytes!("mut_variable.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_variable_fail() {
|
||||
let bytes = include_bytes!("mut_variable_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
// Self
|
||||
#[test]
|
||||
fn test_self_member_pass() {
|
||||
|
9
compiler/tests/circuits/mut_function_fail.leo
Normal file
9
compiler/tests/circuits/mut_function_fail.leo
Normal file
@ -0,0 +1,9 @@
|
||||
circuit Foo {
|
||||
function bar() {}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
f.bar = 1u8;
|
||||
}
|
15
compiler/tests/circuits/mut_self_function_fail.leo
Normal file
15
compiler/tests/circuits/mut_self_function_fail.leo
Normal file
@ -0,0 +1,15 @@
|
||||
circuit Foo {
|
||||
a: u8,
|
||||
|
||||
function bar() {}
|
||||
|
||||
function set_a(new: u8) {
|
||||
self.bar = new;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
f.set_a(1u8);
|
||||
}
|
15
compiler/tests/circuits/mut_self_static_function_fail.leo
Normal file
15
compiler/tests/circuits/mut_self_static_function_fail.leo
Normal file
@ -0,0 +1,15 @@
|
||||
circuit Foo {
|
||||
a: u8,
|
||||
|
||||
static function bar() {}
|
||||
|
||||
function set_a(new: u8) {
|
||||
self.bar = new;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
f.set_a(1u8);
|
||||
}
|
22
compiler/tests/circuits/mut_self_variable.leo
Normal file
22
compiler/tests/circuits/mut_self_variable.leo
Normal file
@ -0,0 +1,22 @@
|
||||
circuit Foo {
|
||||
mut a: u8,
|
||||
|
||||
function set_a(new: u8) {
|
||||
self.a = new;
|
||||
console.assert(self.a == new);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
console.assert(f.a == 0u8);
|
||||
|
||||
f.set_a(1u8);
|
||||
|
||||
console.assert(f.a == 1u8);
|
||||
|
||||
f.set_a(2u8);
|
||||
|
||||
console.assert(f.a == 2u8);
|
||||
}
|
13
compiler/tests/circuits/mut_self_variable_fail.leo
Normal file
13
compiler/tests/circuits/mut_self_variable_fail.leo
Normal file
@ -0,0 +1,13 @@
|
||||
circuit Foo {
|
||||
a: u8,
|
||||
|
||||
function set_a(new: u8) {
|
||||
self.a = new;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
f.set_a(1u8);
|
||||
}
|
9
compiler/tests/circuits/mut_static_function_fail.leo
Normal file
9
compiler/tests/circuits/mut_static_function_fail.leo
Normal file
@ -0,0 +1,9 @@
|
||||
circuit Foo {
|
||||
static function bar() {}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
f.bar = 1u8;
|
||||
}
|
17
compiler/tests/circuits/mut_variable.leo
Normal file
17
compiler/tests/circuits/mut_variable.leo
Normal file
@ -0,0 +1,17 @@
|
||||
circuit Foo {
|
||||
mut a: u8,
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
console.assert(f.a == 0u8);
|
||||
|
||||
f.a = 1u8;
|
||||
|
||||
console.assert(f.a == 1u8);
|
||||
|
||||
f.a = 2u8;
|
||||
|
||||
console.assert(f.a == 2u8);
|
||||
}
|
9
compiler/tests/circuits/mut_variable_fail.leo
Normal file
9
compiler/tests/circuits/mut_variable_fail.leo
Normal file
@ -0,0 +1,9 @@
|
||||
circuit Foo {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
function main() {
|
||||
let mut f = Foo { a: 0u8 };
|
||||
|
||||
f.a = 1u8;
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
use crate::{Expression, Identifier, RangeOrExpression};
|
||||
use leo_ast::{
|
||||
access::AssigneeAccess as AstAssigneeAccess,
|
||||
common::{Assignee as AstAssignee, Identifier as AstIdentifier},
|
||||
common::{Assignee as AstAssignee, Identifier as AstIdentifier, KeywordOrIdentifier},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -38,9 +38,15 @@ impl<'ast> From<AstIdentifier<'ast>> for Assignee {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<KeywordOrIdentifier<'ast>> for Assignee {
|
||||
fn from(name: KeywordOrIdentifier<'ast>) -> Self {
|
||||
Assignee::Identifier(Identifier::from(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<AstAssignee<'ast>> for Assignee {
|
||||
fn from(assignee: AstAssignee<'ast>) -> Self {
|
||||
let variable = Assignee::from(assignee.identifier);
|
||||
let variable = Assignee::from(assignee.name);
|
||||
|
||||
// We start with the id, and we fold the array of accesses by wrapping the current value
|
||||
assignee
|
||||
|
@ -23,8 +23,8 @@ use leo_ast::{
|
||||
use leo_input::common::Identifier as InputAstIdentifier;
|
||||
|
||||
use leo_ast::{
|
||||
common::SelfKeyword,
|
||||
expressions::{CircuitName, KeywordOrIdentifier},
|
||||
common::{KeywordOrIdentifier, SelfKeyword},
|
||||
expressions::CircuitName,
|
||||
functions::InputKeyword,
|
||||
types::SelfType,
|
||||
};
|
||||
|
@ -362,7 +362,7 @@ impl<'ast> From<AstExpression<'ast>> for Expression {
|
||||
// Assignee -> Expression for operator assign statements
|
||||
impl<'ast> From<Assignee<'ast>> for Expression {
|
||||
fn from(assignee: Assignee<'ast>) -> Self {
|
||||
let variable = Expression::Identifier(Identifier::from(assignee.identifier));
|
||||
let variable = Expression::Identifier(Identifier::from(assignee.name));
|
||||
|
||||
// we start with the id, and we fold the array of accesses by wrapping the current value
|
||||
assignee
|
||||
|
Loading…
Reference in New Issue
Block a user