diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d12928e66..94a17e9cac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,49 @@ jobs: command: fmt args: --all -- --check + clippy: + name: Clippy + runs-on: ubuntu-latest + env: + RUSTFLAGS: -Dwarnings + strategy: + matrix: + rust: + - stable + - nightly + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install Rust (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: clippy + + - name: Check examples + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --examples --all + + - name: Check examples with all features on stable + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --examples --all-features --all + if: matrix.rust == 'stable' + + - name: Check benchmarks on nightly + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-features --examples --all --benches + if: matrix.rust == 'nightly' + test: name: Test runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 7b44b12e21..d04a8d65f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1296,7 +1296,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "leo-ast" -version = "1.0.4" +version = "1.0.6" dependencies = [ "criterion", "leo-grammar", @@ -1310,7 +1310,7 @@ dependencies = [ [[package]] name = "leo-compiler" -version = "1.0.4" +version = "1.0.6" dependencies = [ "bincode", "hex", @@ -1345,7 +1345,7 @@ dependencies = [ [[package]] name = "leo-core" -version = "1.0.4" +version = "1.0.6" dependencies = [ "leo-ast", "leo-gadgets", @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "leo-gadgets" -version = "1.0.4" +version = "1.0.6" dependencies = [ "criterion", "rand", @@ -1374,7 +1374,7 @@ dependencies = [ [[package]] name = "leo-grammar" -version = "1.0.4" +version = "1.0.6" dependencies = [ "criterion", "from-pest", @@ -1390,7 +1390,7 @@ dependencies = [ [[package]] name = "leo-imports" -version = "1.0.4" +version = "1.0.6" dependencies = [ "leo-ast", "leo-grammar", @@ -1400,7 +1400,7 @@ dependencies = [ [[package]] name = "leo-input" -version = "1.0.4" +version = "1.0.6" dependencies = [ "from-pest", "pest", @@ -1417,7 +1417,7 @@ dependencies = [ [[package]] name = "leo-lang" -version = "1.0.4" +version = "1.0.6" dependencies = [ "clap", "colored", @@ -1458,11 +1458,11 @@ dependencies = [ [[package]] name = "leo-linter" -version = "1.0.4" +version = "1.0.6" [[package]] name = "leo-package" -version = "1.0.4" +version = "1.0.6" dependencies = [ "lazy_static", "serde", @@ -1476,7 +1476,7 @@ dependencies = [ [[package]] name = "leo-state" -version = "1.0.4" +version = "1.0.6" dependencies = [ "leo-ast", "leo-input", @@ -1495,7 +1495,7 @@ dependencies = [ [[package]] name = "leo-symbol-table" -version = "1.0.4" +version = "1.0.6" dependencies = [ "leo-ast", "leo-core", @@ -1507,7 +1507,7 @@ dependencies = [ [[package]] name = "leo-type-inference" -version = "1.0.4" +version = "1.0.6" dependencies = [ "leo-ast", "leo-grammar", diff --git a/Cargo.toml b/Cargo.toml index b07b3f0a8b..970e89f51e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-lang" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "The Leo programming language" homepage = "https://aleo.org" @@ -37,36 +37,36 @@ members = [ "package", "state", "symbol-table", - "type-inference", + "type-inference" ] [dependencies.leo-ast] path = "./ast" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-compiler] path = "./compiler" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-gadgets] path = "./gadgets" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-imports] path = "./imports" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-input] path = "./input" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-package] path = "./package" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-state] path = "./state" -version = "1.0.4" +version = "1.0.6" [dependencies.snarkos-algorithms] version = "1.1.3" diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 49cc0ae71e..eec77394f0 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-ast" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Core AST of the Leo programming language" homepage = "https://aleo.org" @@ -28,11 +28,11 @@ harness = false [dependencies.leo-grammar] path = "../grammar" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-input] path = "../input" -version = "1.0.4" +version = "1.0.6" [dependencies.snarkos-errors] version = "1.1.3" diff --git a/ast/benches/leo_ast.rs b/ast/benches/leo_ast.rs index 72ab41037c..8c4bab6a53 100644 --- a/ast/benches/leo_ast.rs +++ b/ast/benches/leo_ast.rs @@ -20,64 +20,64 @@ use leo_grammar::Grammar; use criterion::{criterion_group, criterion_main, Criterion}; use std::{path::Path, time::Duration}; -fn ast<'ast>(ast: &Grammar<'ast>) -> Ast { +fn ast(ast: &Grammar) -> Ast { Ast::new("leo_tree", &ast) } fn bench_big_if_else(c: &mut Criterion) { let filepath = Path::new("./big_if_else.leo").to_path_buf(); let program_string = include_str!("./big_if_else.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::big_if_else", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::big_if_else", |b| b.iter(|| ast(&grammar))); } fn bench_big_ternary(c: &mut Criterion) { let filepath = Path::new("./big_ternary.leo").to_path_buf(); let program_string = include_str!("./big_ternary.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::big_ternary", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::big_ternary", |b| b.iter(|| ast(&grammar))); } fn bench_big_circuit(c: &mut Criterion) { let filepath = Path::new("./big_circuit.leo").to_path_buf(); let program_string = include_str!("./big_circuit.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::big_circuit", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::big_circuit", |b| b.iter(|| ast(&grammar))); } fn bench_long_expr(c: &mut Criterion) { let filepath = Path::new("./long_expr.leo").to_path_buf(); let program_string = include_str!("./long_expr.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::long_expr", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::long_expr", |b| b.iter(|| ast(&grammar))); } fn bench_long_array(c: &mut Criterion) { let filepath = Path::new("./long_array.leo").to_path_buf(); let program_string = include_str!("./long_array.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::long_array", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::long_array", |b| b.iter(|| ast(&grammar))); } fn bench_many_foos(c: &mut Criterion) { let filepath = Path::new("./many_foos.leo").to_path_buf(); let program_string = include_str!("./many_foos.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::many_foos", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::many_foos", |b| b.iter(|| ast(&grammar))); } fn bench_many_assigns(c: &mut Criterion) { let filepath = Path::new("./many_assigns.leo").to_path_buf(); let program_string = include_str!("./many_assigns.leo"); - let ast = Grammar::new(&filepath, program_string).unwrap(); + let grammar = Grammar::new(&filepath, program_string).unwrap(); - c.bench_function("Ast::many_assigns", |b| b.iter(|| ast(&ast))); + c.bench_function("Ast::many_assigns", |b| b.iter(|| ast(&grammar))); } criterion_group!( diff --git a/ast/src/circuits/circuit_member.rs b/ast/src/circuits/circuit_member.rs index f8e885dd9d..c86ae4156b 100644 --- a/ast/src/circuits/circuit_member.rs +++ b/ast/src/circuits/circuit_member.rs @@ -15,10 +15,9 @@ // along with the Leo library. If not, see . use crate::{Function, Identifier, Type}; -use leo_grammar::circuits::{ - CircuitFunction as GrammarCircuitFunction, - CircuitMember as GrammarCircuitMember, - CircuitVariableDefinition as GrammarCircuitVariableDefinition, +use leo_grammar::{ + circuits::{CircuitMember as GrammarCircuitMember, CircuitVariableDefinition as GrammarCircuitVariableDefinition}, + functions::Function as GrammarFunction, }; use serde::{Deserialize, Serialize}; @@ -26,28 +25,24 @@ use std::fmt; #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum CircuitMember { - // (is_mutable, variable_name, variable_type) - CircuitVariable(bool, Identifier, Type), - // (is_static, function) - CircuitFunction(bool, Function), + // (variable_name, variable_type) + CircuitVariable(Identifier, Type), + // (function) + CircuitFunction(Function), } impl<'ast> From> for CircuitMember { fn from(circuit_value: GrammarCircuitVariableDefinition<'ast>) -> Self { CircuitMember::CircuitVariable( - circuit_value.mutable.is_some(), Identifier::from(circuit_value.identifier), Type::from(circuit_value.type_), ) } } -impl<'ast> From> for CircuitMember { - fn from(circuit_function: GrammarCircuitFunction<'ast>) -> Self { - CircuitMember::CircuitFunction( - circuit_function._static.is_some(), - Function::from(circuit_function.function), - ) +impl<'ast> From> for CircuitMember { + fn from(circuit_function: GrammarFunction<'ast>) -> Self { + CircuitMember::CircuitFunction(Function::from(circuit_function)) } } @@ -63,16 +58,10 @@ impl<'ast> From> for CircuitMember { impl fmt::Display for CircuitMember { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - CircuitMember::CircuitVariable(ref mutable, ref identifier, ref type_) => { - if *mutable { - write!(f, "mut ")?; - } + CircuitMember::CircuitVariable(ref identifier, ref type_) => { write!(f, "{}: {}", identifier, type_) } - CircuitMember::CircuitFunction(ref static_, ref function) => { - if *static_ { - write!(f, "static ")?; - } + CircuitMember::CircuitFunction(ref function) => { write!(f, "{}", function) } } diff --git a/ast/src/common/identifier.rs b/ast/src/common/identifier.rs index e6f3f4baf2..84dc49fa87 100644 --- a/ast/src/common/identifier.rs +++ b/ast/src/common/identifier.rs @@ -14,12 +14,18 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::Span; +use crate::{InputKeyword, MutSelfKeyword, SelfKeyword, Span}; use leo_grammar::{ annotations::AnnotationArgument, - common::{Identifier as GrammarIdentifier, KeywordOrIdentifier, SelfKeyword, SelfKeywordOrIdentifier}, + common::{ + Identifier as GrammarIdentifier, + KeywordOrIdentifier, + MutSelfKeyword as GrammarMutSelfKeyword, + SelfKeyword as GrammarSelfKeyword, + SelfKeywordOrIdentifier, + }, expressions::CircuitName, - functions::InputKeyword, + functions::InputKeyword as GrammarInputKeyword, imports::PackageName as GrammarPackageName, types::SelfType, }; @@ -128,20 +134,56 @@ impl<'ast> From> for Identifier { } } -impl<'ast> From> for Identifier { - fn from(self_: SelfKeyword<'ast>) -> Self { +impl<'ast> From> for Identifier { + fn from(grammar: GrammarSelfKeyword<'ast>) -> Self { Self { - name: self_.keyword, - span: Span::from(self_.span), + name: grammar.keyword, + span: Span::from(grammar.span), } } } -impl<'ast> From> for Identifier { - fn from(input: InputKeyword<'ast>) -> Self { +impl From for Identifier { + fn from(keyword: SelfKeyword) -> Self { Self { - name: input.keyword, - span: Span::from(input.span), + name: keyword.to_string(), + span: keyword.span, + } + } +} + +impl<'ast> From> for Identifier { + fn from(grammar: GrammarMutSelfKeyword<'ast>) -> Self { + Self { + name: grammar.to_string(), + span: Span::from(grammar.span), + } + } +} + +impl From for Identifier { + fn from(keyword: MutSelfKeyword) -> Self { + Self { + name: keyword.to_string(), + span: keyword.span, + } + } +} + +impl<'ast> From> for Identifier { + fn from(grammar: GrammarInputKeyword<'ast>) -> Self { + Self { + name: grammar.keyword, + span: Span::from(grammar.span), + } + } +} + +impl From for Identifier { + fn from(keyword: InputKeyword) -> Self { + Self { + name: keyword.to_string(), + span: keyword.span, } } } diff --git a/ast/src/common/input_keyword.rs b/ast/src/common/input_keyword.rs new file mode 100644 index 0000000000..5df0aa7b08 --- /dev/null +++ b/ast/src/common/input_keyword.rs @@ -0,0 +1,42 @@ +// 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 . + +use crate::Span; +use leo_grammar::functions::InputKeyword as GrammarInputKeyword; + +use serde::{Deserialize, Serialize}; +use std::fmt; + +/// The `input` keyword can view program register, record, and state values. +/// Values cannot be modified. The `input` keyword cannot be made mutable. +#[derive(Clone, Serialize, Deserialize)] +pub struct InputKeyword { + pub span: Span, +} + +impl<'ast> From> for InputKeyword { + fn from(grammar: GrammarInputKeyword<'ast>) -> Self { + Self { + span: Span::from(grammar.span), + } + } +} + +impl fmt::Display for InputKeyword { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "input") + } +} diff --git a/ast/src/common/mod.rs b/ast/src/common/mod.rs index 382d82142c..4d20d843aa 100644 --- a/ast/src/common/mod.rs +++ b/ast/src/common/mod.rs @@ -26,12 +26,21 @@ pub use declare::*; pub mod identifier; pub use identifier::*; +pub mod input_keyword; +pub use input_keyword::*; + +pub mod mut_self_keyword; +pub use mut_self_keyword::*; + pub mod positive_number; pub use positive_number::*; pub mod range_or_expression; pub use range_or_expression::*; +pub mod self_keyword; +pub use self_keyword::*; + pub mod span; pub use span::*; diff --git a/symbol-table/src/types/circuits/circuit_function.rs b/ast/src/common/mut_self_keyword.rs similarity index 55% rename from symbol-table/src/types/circuits/circuit_function.rs rename to ast/src/common/mut_self_keyword.rs index 4c6d8686a9..b11a8df0ac 100644 --- a/symbol-table/src/types/circuits/circuit_function.rs +++ b/ast/src/common/mut_self_keyword.rs @@ -14,14 +14,28 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{types::FunctionType, Attribute}; +use crate::Span; +use leo_grammar::common::MutSelfKeyword as GrammarMutSelfKeyword; use serde::{Deserialize, Serialize}; +use std::fmt; -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct CircuitFunctionType { - /// The function signature of the circuit function - pub function: FunctionType, - /// The attributes of the circuit function - pub attribute: Option, +/// The `mut self` keyword can view and modify circuit values inside of a circuit function. +#[derive(Clone, Serialize, Deserialize)] +pub struct MutSelfKeyword { + pub span: Span, +} + +impl<'ast> From> for MutSelfKeyword { + fn from(grammar: GrammarMutSelfKeyword<'ast>) -> Self { + Self { + span: Span::from(grammar.span), + } + } +} + +impl fmt::Display for MutSelfKeyword { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "mut self") + } } diff --git a/ast/src/common/self_keyword.rs b/ast/src/common/self_keyword.rs new file mode 100644 index 0000000000..8dfdfecc70 --- /dev/null +++ b/ast/src/common/self_keyword.rs @@ -0,0 +1,42 @@ +// 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 . + +use crate::Span; +use leo_grammar::common::SelfKeyword as GrammarSelfKeyword; + +use serde::{Deserialize, Serialize}; +use std::fmt; + +/// The `self` keyword can view circuit values inside of a circuit function. +/// Circuit values cannot be modified. To modify values use the `mut self` [MutSelfKeyword]. +#[derive(Clone, Serialize, Deserialize)] +pub struct SelfKeyword { + pub span: Span, +} + +impl<'ast> From> for SelfKeyword { + fn from(grammar: GrammarSelfKeyword<'ast>) -> Self { + Self { + span: Span::from(grammar.span), + } + } +} + +impl fmt::Display for SelfKeyword { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "self") + } +} diff --git a/ast/src/functions/function.rs b/ast/src/functions/function.rs index be15d5131e..c55daf03d3 100644 --- a/ast/src/functions/function.rs +++ b/ast/src/functions/function.rs @@ -60,6 +60,32 @@ impl Function { &self.identifier.name } + /// + /// Returns `true` if the function has input `self` or `mut self`. + /// Returns `false` otherwise. + /// + pub fn contains_self(&self) -> bool { + self.input.iter().any(|param| param.is_self()) + } + + /// + /// Returns `true` if the function has input `mut self`. + /// Returns `false` otherwise. + /// + pub fn contains_mut_self(&self) -> bool { + self.input.iter().any(|param| param.is_mut_self()) + } + + /// + /// Returns a vector of [&FunctionInput] removing `self` and `mut self` inputs. + /// + pub fn filter_self_inputs(&self) -> Vec<&FunctionInput> { + self.input + .iter() + .filter(|input| !input.is_self()) + .collect::>() + } + fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "function {}", self.identifier)?; diff --git a/ast/src/functions/input/input_variable.rs b/ast/src/functions/input/input_variable.rs index cc7c75231c..3286496b89 100644 --- a/ast/src/functions/input/input_variable.rs +++ b/ast/src/functions/input/input_variable.rs @@ -14,29 +14,27 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{FunctionInputVariable, Identifier, Span}; +use crate::{FunctionInputVariable, InputKeyword, MutSelfKeyword, SelfKeyword}; use leo_grammar::functions::input::Input as GrammarInput; use serde::{Deserialize, Serialize}; use std::fmt; -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +/// Enumerates the possible inputs to a function. +#[derive(Clone, Serialize, Deserialize)] pub enum FunctionInput { - InputKeyword(Identifier), + InputKeyword(InputKeyword), + SelfKeyword(SelfKeyword), + MutSelfKeyword(MutSelfKeyword), Variable(FunctionInputVariable), } impl<'ast> From> for FunctionInput { fn from(input: GrammarInput<'ast>) -> Self { match input { - GrammarInput::InputKeyword(input_keyword) => { - let id = Identifier { - name: input_keyword.keyword, - span: Span::from(input_keyword.span), - }; - - FunctionInput::InputKeyword(id) - } + GrammarInput::InputKeyword(keyword) => FunctionInput::InputKeyword(InputKeyword::from(keyword)), + GrammarInput::SelfKeyword(keyword) => FunctionInput::SelfKeyword(SelfKeyword::from(keyword)), + GrammarInput::MutSelfKeyword(keyword) => FunctionInput::MutSelfKeyword(MutSelfKeyword::from(keyword)), GrammarInput::FunctionInput(function_input) => { FunctionInput::Variable(FunctionInputVariable::from(function_input)) } @@ -45,9 +43,37 @@ impl<'ast> From> for FunctionInput { } impl FunctionInput { + /// + /// Returns `true` if the function input is the `self` or `mut self` keyword. + /// Returns `false` otherwise. + /// + pub fn is_self(&self) -> bool { + match self { + FunctionInput::InputKeyword(_) => false, + FunctionInput::SelfKeyword(_) => true, + FunctionInput::MutSelfKeyword(_) => true, + FunctionInput::Variable(_) => false, + } + } + + /// + /// 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(id) => write!(f, "{}", id), + FunctionInput::InputKeyword(keyword) => write!(f, "{}", keyword), + FunctionInput::SelfKeyword(keyword) => write!(f, "{}", keyword), + FunctionInput::MutSelfKeyword(keyword) => write!(f, "{}", keyword), FunctionInput::Variable(function_input) => write!(f, "{}", function_input), } } @@ -64,3 +90,18 @@ impl fmt::Debug for FunctionInput { self.format(f) } } + +impl PartialEq for FunctionInput { + /// Returns true if `self == other`. Does not compare spans. + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (FunctionInput::InputKeyword(_), FunctionInput::InputKeyword(_)) => true, + (FunctionInput::SelfKeyword(_), FunctionInput::SelfKeyword(_)) => true, + (FunctionInput::MutSelfKeyword(_), FunctionInput::MutSelfKeyword(_)) => true, + (FunctionInput::Variable(left), FunctionInput::Variable(right)) => left.eq(right), + _ => false, + } + } +} + +impl Eq for FunctionInput {} diff --git a/ast/src/input/input_value.rs b/ast/src/input/input_value.rs index 1f6124e518..975b99dd17 100644 --- a/ast/src/input/input_value.rs +++ b/ast/src/input/input_value.rs @@ -53,8 +53,8 @@ impl InputValue { Ok(InputValue::Boolean(boolean)) } - fn from_number(integer_type: IntegerType, number: String) -> Result { - Ok(InputValue::Integer(integer_type, number)) + fn from_number(integer_type: IntegerType, number: String) -> Self { + InputValue::Integer(integer_type, number) } fn from_group(group: InputGroupValue) -> Self { @@ -69,7 +69,7 @@ impl InputValue { match data_type { DataType::Address(_) => Err(InputParserError::implicit_type(data_type, implicit)), DataType::Boolean(_) => Err(InputParserError::implicit_type(data_type, implicit)), - DataType::Integer(integer_type) => InputValue::from_number(integer_type, implicit.to_string()), + DataType::Integer(integer_type) => Ok(InputValue::from_number(integer_type, implicit.to_string())), DataType::Group(_) => Err(InputParserError::implicit_group(implicit)), DataType::Field(_) => Ok(InputValue::Field(implicit.to_string())), } @@ -80,7 +80,7 @@ impl InputValue { (DataType::Address(_), Value::Address(address)) => Ok(InputValue::from_address_value(address)), (DataType::Boolean(_), Value::Boolean(boolean)) => InputValue::from_boolean(boolean), (DataType::Integer(integer_type), Value::Integer(integer)) => { - InputValue::from_number(integer_type, integer.to_string()) + Ok(InputValue::from_number(integer_type, integer.to_string())) } (DataType::Group(_), Value::Group(group)) => Ok(InputValue::from_group(group)), (DataType::Field(_), Value::Field(field)) => Ok(InputValue::from_field(field)), diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 7cb81be57c..cbf0636741 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-compiler" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Compiler of the Leo programming language" homepage = "https://aleo.org" @@ -19,43 +19,43 @@ edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-core] path = "../core" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-gadgets] path = "../gadgets" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-grammar] path = "../grammar" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-imports] path = "../imports" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-input] path = "../input" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-package] path = "../package" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-state] path = "../state" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-symbol-table] path = "../symbol-table" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-type-inference] path = "../type-inference" -version = "1.0.4" +version = "1.0.6" [dependencies.snarkos-curves] version = "1.1.3" diff --git a/compiler/src/errors/expression.rs b/compiler/src/errors/expression.rs index 41a83cd6f2..be0deb5925 100644 --- a/compiler/src/errors/expression.rs +++ b/compiler/src/errors/expression.rs @@ -206,7 +206,7 @@ impl ExpressionError { } pub fn undefined_identifier(identifier: Identifier) -> Self { - let message = format!("cannot find value `{}` in this scope", identifier.name); + let message = format!("Cannot find value `{}` in this scope", identifier.name); Self::new_from_span(message, identifier.span) } diff --git a/compiler/src/errors/function.rs b/compiler/src/errors/function.rs index 8f22e1fb87..49dfae9467 100644 --- a/compiler/src/errors/function.rs +++ b/compiler/src/errors/function.rs @@ -82,12 +82,6 @@ impl FunctionError { FunctionError::Error(FormattedError::new_from_span(message, span)) } - pub fn arguments_length(expected: usize, actual: usize, span: Span) -> Self { - let message = format!("function expected {} input variables, found {}", expected, actual); - - Self::new_from_span(message, span) - } - pub fn invalid_array(actual: String, span: Span) -> Self { let message = format!("Expected function input array, found `{}`", actual); diff --git a/compiler/src/expression/circuit/access.rs b/compiler/src/expression/circuit/access.rs index 0d3864c295..4172c8c476 100644 --- a/compiler/src/expression/circuit/access.rs +++ b/compiler/src/expression/circuit/access.rs @@ -67,14 +67,17 @@ impl> ConstrainedProgram { match matched_member { Some(member) => { match &member.1 { - ConstrainedValue::Function(ref _circuit_identifier, ref _function) => { - // Pass circuit members into function call by value - for stored_member in members { - let circuit_scope = new_scope(&file_scope, &circuit_name.name); - let self_keyword = new_scope(&circuit_scope, SELF_KEYWORD); - let variable = new_scope(&self_keyword, &stored_member.0.name); + ConstrainedValue::Function(ref _circuit_identifier, ref function) => { + // Check for function input `self` or `mut self`. + if function.contains_self() { + // Pass circuit members into function call by value + for stored_member in members { + let circuit_scope = new_scope(&file_scope, &circuit_name.name); + let self_keyword = new_scope(&circuit_scope, SELF_KEYWORD); + let variable = new_scope(&self_keyword, &stored_member.0.name); - self.store(variable, stored_member.1.clone()); + self.store(variable, stored_member.1.clone()); + } } } ConstrainedValue::Static(value) => { diff --git a/compiler/src/expression/circuit/circuit.rs b/compiler/src/expression/circuit/circuit.rs index e78cd00e91..6a6e129fe3 100644 --- a/compiler/src/expression/circuit/circuit.rs +++ b/compiler/src/expression/circuit/circuit.rs @@ -58,7 +58,7 @@ impl> ConstrainedProgram { for member in circuit.members.into_iter() { match member { - CircuitMember::CircuitVariable(is_mutable, identifier, type_) => { + CircuitMember::CircuitVariable(identifier, type_) => { let matched_variable = members .clone() .into_iter() @@ -66,7 +66,7 @@ impl> ConstrainedProgram { match matched_variable { Some(variable) => { // Resolve and enforce circuit variable - let mut variable_value = self.enforce_expression( + let variable_value = self.enforce_expression( cs, file_scope, function_scope, @@ -74,25 +74,16 @@ impl> ConstrainedProgram { variable.expression, )?; - // Add mutability to circuit variable - if is_mutable { - variable_value = ConstrainedValue::Mutable(Box::new(variable_value)) - } - resolved_members.push(ConstrainedCircuitMember(identifier, variable_value)) } None => return Err(ExpressionError::expected_circuit_member(identifier.to_string(), span)), } } - CircuitMember::CircuitFunction(_static, function) => { + CircuitMember::CircuitFunction(function) => { let identifier = function.identifier.clone(); - let mut constrained_function_value = + let constrained_function_value = ConstrainedValue::Function(Some(circuit_identifier.clone()), function); - if _static { - constrained_function_value = ConstrainedValue::Static(Box::new(constrained_function_value)); - } - resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value)); } }; diff --git a/compiler/src/expression/circuit/static_access.rs b/compiler/src/expression/circuit/static_access.rs index 31ed5bb865..27086ac55c 100644 --- a/compiler/src/expression/circuit/static_access.rs +++ b/compiler/src/expression/circuit/static_access.rs @@ -56,22 +56,13 @@ impl> ConstrainedProgram { // Find static circuit function let matched_function = circuit.members.into_iter().find(|member| match member { - CircuitMember::CircuitFunction(_static, function) => function.identifier == circuit_member, + CircuitMember::CircuitFunction(function) => function.identifier == circuit_member, _ => false, }); // Return errors if no static function exists let function = match matched_function { - Some(CircuitMember::CircuitFunction(_static, function)) => { - if _static { - function - } else { - return Err(ExpressionError::invalid_member_access( - function.identifier.to_string(), - span, - )); - } - } + Some(CircuitMember::CircuitFunction(function)) => function, _ => { return Err(ExpressionError::undefined_member_access( circuit.circuit_name.to_string(), diff --git a/compiler/src/function/function.rs b/compiler/src/function/function.rs index ea79ddeb46..53ac0a82ba 100644 --- a/compiler/src/function/function.rs +++ b/compiler/src/function/function.rs @@ -23,22 +23,13 @@ use crate::{ GroupType, }; -use leo_ast::{Expression, Function, FunctionInput, Span}; +use leo_ast::{Expression, Function, FunctionInput}; use snarkos_models::{ curves::{Field, PrimeField}, gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, }; -pub fn check_arguments_length(expected: usize, actual: usize, span: &Span) -> Result<(), FunctionError> { - // Make sure we are given the correct number of arguments - if expected != actual { - Err(FunctionError::arguments_length(expected, actual, span.to_owned())) - } else { - Ok(()) - } -} - impl> ConstrainedProgram { pub(crate) fn enforce_function>( &mut self, @@ -51,17 +42,29 @@ impl> ConstrainedProgram { ) -> Result, FunctionError> { let function_name = new_scope(scope, function.get_name()); - // Make sure we are given the correct number of input variables - check_arguments_length(function.input.len(), input.len(), &function.span)?; + // Store if function contains input `mut self`. + let mut_self = function.contains_mut_self(); // Store input values as new variables in resolved program - for (input_model, input_expression) in function.input.iter().zip(input.into_iter()) { + for (input_model, input_expression) in function.filter_self_inputs().iter().zip(input.into_iter()) { let (name, value) = match input_model { - FunctionInput::InputKeyword(identifier) => { - let input_value = + FunctionInput::InputKeyword(keyword) => { + let value = self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; - (&identifier.name, input_value) + (keyword.to_string(), value) + } + FunctionInput::SelfKeyword(keyword) => { + let value = + self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; + + (keyword.to_string(), value) + } + FunctionInput::MutSelfKeyword(keyword) => { + let value = + self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?; + + (keyword.to_string(), value) } FunctionInput::Variable(input_model) => { // First evaluate input expression @@ -78,7 +81,7 @@ impl> ConstrainedProgram { input_value = ConstrainedValue::Mutable(Box::new(input_value)) } - (&input_model.identifier.name, input_value) + (input_model.identifier.name.clone(), input_value) } }; @@ -100,6 +103,7 @@ impl> ConstrainedProgram { statement.clone(), function.output.clone(), declared_circuit_reference, + mut_self, )?; results.append(&mut result); diff --git a/compiler/src/function/input/input_keyword.rs b/compiler/src/function/input/input_keyword.rs index 5d74e55f70..3d40090a3f 100644 --- a/compiler/src/function/input/input_keyword.rs +++ b/compiler/src/function/input/input_keyword.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType}; -use leo_ast::{Identifier, Input}; +use leo_ast::{Identifier, Input, InputKeyword}; use snarkos_models::{ curves::{Field, PrimeField}, @@ -31,26 +31,26 @@ impl> ConstrainedProgram { pub fn allocate_input_keyword>( &mut self, cs: &mut CS, - identifier: Identifier, + keyword: InputKeyword, input: &Input, ) -> Result, FunctionError> { // Create an identifier for each input variable let registers_name = Identifier { name: REGISTERS_VARIABLE_NAME.to_string(), - span: identifier.span.clone(), + span: keyword.span.clone(), }; let record_name = Identifier { name: RECORD_VARIABLE_NAME.to_string(), - span: identifier.span.clone(), + span: keyword.span.clone(), }; let state_name = Identifier { name: STATE_VARIABLE_NAME.to_string(), - span: identifier.span.clone(), + span: keyword.span.clone(), }; let state_leaf_name = Identifier { name: STATE_LEAF_VARIABLE_NAME.to_string(), - span: identifier.span.clone(), + span: keyword.span.clone(), }; // Fetch each input variable's definitions @@ -82,6 +82,6 @@ impl> ConstrainedProgram { // Return input variable keyword as circuit expression - Ok(ConstrainedValue::CircuitExpression(identifier, members)) + Ok(ConstrainedValue::CircuitExpression(Identifier::from(keyword), members)) } } diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index 7604a80b28..1d3f5d1380 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -23,7 +23,7 @@ use crate::{ OutputBytes, }; -use leo_ast::{Expression, Function, FunctionInput, Input}; +use leo_ast::{Expression, Function, FunctionInput, Identifier, Input}; use snarkos_models::{ curves::{Field, PrimeField}, @@ -44,11 +44,16 @@ impl> ConstrainedProgram { // Iterate over main function input variables and allocate new values let mut input_variables = Vec::with_capacity(function.input.len()); for input_model in function.input.clone().into_iter() { - let (identifier, value) = match input_model { - FunctionInput::InputKeyword(identifier) => { - let value = self.allocate_input_keyword(cs, identifier.clone(), &input)?; + let (input_id, value) = match input_model { + FunctionInput::InputKeyword(keyword) => { + let input_id = Identifier::new_with_span(&keyword.to_string(), &keyword.span); + let value = self.allocate_input_keyword(cs, keyword, &input)?; - (identifier, value) + (input_id, value) + } + FunctionInput::SelfKeyword(_) => unimplemented!("cannot access self keyword in main function"), + FunctionInput::MutSelfKeyword(_) => { + unimplemented!("cannot access mut self keyword in main function") } FunctionInput::Variable(input_model) => { let name = input_model.identifier.name.clone(); @@ -63,12 +68,12 @@ impl> ConstrainedProgram { }; // Store input as variable with {function_name}_{identifier_name} - let input_name = new_scope(&function_name, &identifier.name); + let input_name = new_scope(&function_name, &input_id.to_string()); // Store a new variable for every allocated main function input self.store(input_name, value); - input_variables.push(Expression::Identifier(identifier)); + input_variables.push(Expression::Identifier(input_id)); } let span = function.span.clone(); diff --git a/compiler/src/statement/assign/assign.rs b/compiler/src/statement/assign/assign.rs index 25006a05e6..27c1ecd0f8 100644 --- a/compiler/src/statement/assign/assign.rs +++ b/compiler/src/statement/assign/assign.rs @@ -43,6 +43,7 @@ impl> ConstrainedProgram { function_scope: &str, declared_circuit_reference: &str, indicator: &Boolean, + mut_self: bool, assignee: Assignee, expression: Expression, span: &Span, @@ -87,7 +88,7 @@ impl> ConstrainedProgram { } 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( diff --git a/compiler/src/statement/assign/circuit_variable.rs b/compiler/src/statement/assign/circuit_variable.rs index 60d0ebb7f6..40f6666671 100644 --- a/compiler/src/statement/assign/circuit_variable.rs +++ b/compiler/src/statement/assign/circuit_variable.rs @@ -59,9 +59,7 @@ impl> ConstrainedProgram { span.to_owned(), )) } - ConstrainedValue::Mutable(value) => { - // Mutate the circuit variable's value in place - + value => { // Check that the new value type == old value type new_value.resolve_type(Some(value.to_type(span)?), span)?; @@ -87,13 +85,6 @@ impl> ConstrainedProgram { Ok(selected_value) } - _ => { - // Throw an error if we try to mutate an immutable circuit variable - Err(StatementError::immutable_circuit_variable( - variable_name.name, - span.to_owned(), - )) - } }, None => { // Throw an error if the circuit variable does not exist in the circuit diff --git a/compiler/src/statement/branch/branch.rs b/compiler/src/statement/branch/branch.rs index f948c85a73..862ddbf8ff 100644 --- a/compiler/src/statement/branch/branch.rs +++ b/compiler/src/statement/branch/branch.rs @@ -25,6 +25,9 @@ use snarkos_models::{ }; impl> ConstrainedProgram { + /// Evaluates a branch of one or more statements and returns a result in + /// the given scope. + #[allow(clippy::too_many_arguments)] pub fn evaluate_branch>( &mut self, cs: &mut CS, @@ -33,6 +36,7 @@ impl> ConstrainedProgram { indicator: &Boolean, statements: Vec, return_type: Option, + mut_self: bool, ) -> StatementResult>> { let mut results = Vec::with_capacity(statements.len()); // Evaluate statements. Only allow a single return argument to be returned. @@ -45,6 +49,7 @@ impl> ConstrainedProgram { statement, return_type.clone(), "", + mut_self, )?; results.append(&mut value); diff --git a/compiler/src/statement/conditional/conditional.rs b/compiler/src/statement/conditional/conditional.rs index 94e3a8726e..02246e2e27 100644 --- a/compiler/src/statement/conditional/conditional.rs +++ b/compiler/src/statement/conditional/conditional.rs @@ -52,6 +52,7 @@ impl> ConstrainedProgram { indicator: &Boolean, statement: ConditionalStatement, return_type: Option, + mut_self: bool, span: &Span, ) -> StatementResult>> { let statement_string = statement.to_string(); @@ -95,6 +96,7 @@ impl> ConstrainedProgram { &branch_1_indicator, statement.statements, return_type.clone(), + mut_self, )?; results.append(&mut branch_1_result); @@ -123,6 +125,7 @@ impl> ConstrainedProgram { &branch_2_indicator, *nested, return_type, + mut_self, span, )?, ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch( @@ -132,6 +135,7 @@ impl> ConstrainedProgram { &branch_2_indicator, statements, return_type, + mut_self, )?, }, None => vec![], diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index 509d4c22bd..e5c33c6a58 100644 --- a/compiler/src/statement/iteration/iteration.rs +++ b/compiler/src/statement/iteration/iteration.rs @@ -48,6 +48,7 @@ impl> ConstrainedProgram { stop: Expression, statements: Vec, return_type: Option, + mut_self: bool, span: &Span, ) -> StatementResult>> { let mut results = vec![]; @@ -74,6 +75,7 @@ impl> ConstrainedProgram { indicator, statements.clone(), return_type.clone(), + mut_self, )?; results.append(&mut result); diff --git a/compiler/src/statement/statement.rs b/compiler/src/statement/statement.rs index 854d46c7cc..61ad80c87a 100644 --- a/compiler/src/statement/statement.rs +++ b/compiler/src/statement/statement.rs @@ -45,6 +45,7 @@ impl> ConstrainedProgram { statement: Statement, return_type: Option, declared_circuit_reference: &str, + mut_self: bool, ) -> StatementResult>> { let mut results = vec![]; @@ -75,6 +76,7 @@ impl> ConstrainedProgram { function_scope, declared_circuit_reference, indicator, + mut_self, variable, expression, &span, @@ -88,6 +90,7 @@ impl> ConstrainedProgram { indicator, statement, return_type, + mut_self, &span, )?; @@ -104,6 +107,7 @@ impl> ConstrainedProgram { start_stop.1, statements, return_type, + mut_self, &span, )?; diff --git a/compiler/tests/circuits/define_circuit_inside_circuit_function.leo b/compiler/tests/circuits/define_circuit_inside_circuit_function.leo index 17a8522b97..8c25c1e9d9 100644 --- a/compiler/tests/circuits/define_circuit_inside_circuit_function.leo +++ b/compiler/tests/circuits/define_circuit_inside_circuit_function.leo @@ -3,7 +3,7 @@ circuit Foo { } circuit Bar { - static function bar() { + function bar() { let f = Foo { a: 0u32 }; } } diff --git a/compiler/tests/circuits/member_function_invalid.leo b/compiler/tests/circuits/member_function_invalid.leo index d0a7271a07..bb834e9562 100644 --- a/compiler/tests/circuits/member_function_invalid.leo +++ b/compiler/tests/circuits/member_function_invalid.leo @@ -1,5 +1,5 @@ circuit Foo { - static function echo(x: u32) -> u32 { + function echo(x: u32) -> u32 { return x } } diff --git a/compiler/tests/circuits/member_function_nested.leo b/compiler/tests/circuits/member_function_nested.leo index 4146ef9492..9e07cc9acf 100644 --- a/compiler/tests/circuits/member_function_nested.leo +++ b/compiler/tests/circuits/member_function_nested.leo @@ -1,18 +1,18 @@ circuit Foo { x: u32, - function add_x(y: u32) -> u32 { + function add_x(self, y: u32) -> u32 { return self.x + y } - function call_add_x(y: u32) -> u32 { + function call_add_x(self, y: u32) -> u32 { return self.add_x(y) } } function main() { let a = Foo { x: 1u32 }; - let b = a.call_add_x(1u32); + let b = a.add_x(1u32); console.assert(b == 2u32); } diff --git a/compiler/tests/circuits/member_static_function.leo b/compiler/tests/circuits/member_static_function.leo index ac96c89088..4bf51190f0 100644 --- a/compiler/tests/circuits/member_static_function.leo +++ b/compiler/tests/circuits/member_static_function.leo @@ -1,5 +1,5 @@ circuit Foo { - static function echo(x: u32) -> u32 { + function echo(x: u32) -> u32 { return x } } diff --git a/compiler/tests/circuits/member_static_function_invalid.leo b/compiler/tests/circuits/member_static_function_invalid.leo index b2782bfed4..513d78b67d 100644 --- a/compiler/tests/circuits/member_static_function_invalid.leo +++ b/compiler/tests/circuits/member_static_function_invalid.leo @@ -5,5 +5,5 @@ circuit Foo { } function main() { - let err = Foo::echo(1u32); // echo is a non-static function and must be accessed using `.` + let err = Foo::echo(1u32); // Correct, echo is a static function and must be accessed using `::` } \ No newline at end of file diff --git a/compiler/tests/circuits/member_static_function_nested.leo b/compiler/tests/circuits/member_static_function_nested.leo index 8f717f3f7c..ef536e3f6e 100644 --- a/compiler/tests/circuits/member_static_function_nested.leo +++ b/compiler/tests/circuits/member_static_function_nested.leo @@ -1,11 +1,11 @@ circuit Foo { - static function qux() {} + function qux() {} - static function bar() { + function bar() { Self::qux(); } - static function baz() { + function baz() { Self::bar(); } } diff --git a/compiler/tests/circuits/member_static_function_undefined.leo b/compiler/tests/circuits/member_static_function_undefined.leo index e8e5cb20bc..cf9f98c7b4 100644 --- a/compiler/tests/circuits/member_static_function_undefined.leo +++ b/compiler/tests/circuits/member_static_function_undefined.leo @@ -1,5 +1,5 @@ circuit Foo { - static function echo(x: u32) -> u32 { + function echo(x: u32) -> u32 { return x } } diff --git a/compiler/tests/circuits/member_variable_and_function.leo b/compiler/tests/circuits/member_variable_and_function.leo index 35f413a361..074feab7b8 100644 --- a/compiler/tests/circuits/member_variable_and_function.leo +++ b/compiler/tests/circuits/member_variable_and_function.leo @@ -1,7 +1,7 @@ circuit Foo { foo: u32, - static function bar() -> u32 { + function bar() -> u32 { return 1u32 } } diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 33d0d41ea9..848d7a01c7 100644 --- a/compiler/tests/circuits/mod.rs +++ b/compiler/tests/circuits/mod.rs @@ -119,9 +119,9 @@ fn test_member_static_function_nested() { #[test] fn test_member_static_function_invalid() { let bytes = include_bytes!("member_static_function_invalid.leo"); - let error = parse_program(bytes).err().unwrap(); + let program = parse_program(bytes).unwrap(); - expect_type_inference_error(error) + assert_satisfied(program) } #[test] @@ -219,9 +219,9 @@ fn test_self_member_pass() { #[test] fn test_self_member_invalid() { let bytes = include_bytes!("self_member_invalid.leo"); - let program = parse_program(bytes).unwrap(); + let error = parse_program(bytes).err().unwrap(); - let _err = expect_compiler_error(program); + expect_type_inference_error(error); } #[test] diff --git a/compiler/tests/circuits/mut_self_function_fail.leo b/compiler/tests/circuits/mut_self_function_fail.leo index 18da32c5fb..8c9b99f6ae 100644 --- a/compiler/tests/circuits/mut_self_function_fail.leo +++ b/compiler/tests/circuits/mut_self_function_fail.leo @@ -3,7 +3,7 @@ circuit Foo { function bar() {} - function set_a(new: u8) { + function set_a(mut self, new: u8) { self.bar = new; } } diff --git a/compiler/tests/circuits/mut_self_static_function_fail.leo b/compiler/tests/circuits/mut_self_static_function_fail.leo index de87c5fadf..8c9b99f6ae 100644 --- a/compiler/tests/circuits/mut_self_static_function_fail.leo +++ b/compiler/tests/circuits/mut_self_static_function_fail.leo @@ -1,9 +1,9 @@ circuit Foo { a: u8, - static function bar() {} + function bar() {} - function set_a(new: u8) { + function set_a(mut self, new: u8) { self.bar = new; } } diff --git a/compiler/tests/circuits/mut_self_variable.leo b/compiler/tests/circuits/mut_self_variable.leo index 47b9aeed70..f5a35ec754 100644 --- a/compiler/tests/circuits/mut_self_variable.leo +++ b/compiler/tests/circuits/mut_self_variable.leo @@ -1,7 +1,7 @@ circuit Foo { - mut a: u8, + a: u8, - function set_a(new: u8) { + function set_a(mut self, new: u8) { self.a = new; console.assert(self.a == new); } diff --git a/compiler/tests/circuits/mut_self_variable_fail.leo b/compiler/tests/circuits/mut_self_variable_fail.leo index 551b041c9e..fdbb556bca 100644 --- a/compiler/tests/circuits/mut_self_variable_fail.leo +++ b/compiler/tests/circuits/mut_self_variable_fail.leo @@ -1,7 +1,7 @@ circuit Foo { a: u8, - function set_a(new: u8) { + function set_a(self, new: u8) { self.a = new; } } diff --git a/compiler/tests/circuits/mut_static_function_fail.leo b/compiler/tests/circuits/mut_static_function_fail.leo index f1bccaaf89..ed3092c656 100644 --- a/compiler/tests/circuits/mut_static_function_fail.leo +++ b/compiler/tests/circuits/mut_static_function_fail.leo @@ -1,5 +1,5 @@ circuit Foo { - static function bar() {} + function bar() {} } function main() { diff --git a/compiler/tests/circuits/mut_variable.leo b/compiler/tests/circuits/mut_variable.leo index eaf61ddf02..243d7a2cf2 100644 --- a/compiler/tests/circuits/mut_variable.leo +++ b/compiler/tests/circuits/mut_variable.leo @@ -1,5 +1,5 @@ circuit Foo { - mut a: u8, + a: u8, } function main() { diff --git a/compiler/tests/circuits/mut_variable_fail.leo b/compiler/tests/circuits/mut_variable_fail.leo index bb2e653ee3..4d58150c95 100644 --- a/compiler/tests/circuits/mut_variable_fail.leo +++ b/compiler/tests/circuits/mut_variable_fail.leo @@ -3,7 +3,7 @@ circuit Foo { } function main() { - let mut f = Foo { a: 0u8 }; + let f = Foo { a: 0u8 }; f.a = 1u8; } \ No newline at end of file diff --git a/compiler/tests/circuits/pedersen_mock.leo b/compiler/tests/circuits/pedersen_mock.leo index 2b58019d8d..0b42c64a6e 100644 --- a/compiler/tests/circuits/pedersen_mock.leo +++ b/compiler/tests/circuits/pedersen_mock.leo @@ -1,11 +1,11 @@ circuit PedersenHash { parameters: [u32; 512] - static function new(parameters: [u32; 512]) -> Self { + function new(parameters: [u32; 512]) -> Self { return Self { parameters: parameters } } - function hash(bits: [bool; 512]) -> u32 { + function hash(self, bits: [bool; 512]) -> u32 { let mut digest: u32 = 0; for i in 0..512 { let base = if bits[i] ? self.parameters[i] : 0u32; diff --git a/compiler/tests/circuits/self_member.leo b/compiler/tests/circuits/self_member.leo index a075894af0..1bd978433d 100644 --- a/compiler/tests/circuits/self_member.leo +++ b/compiler/tests/circuits/self_member.leo @@ -1,7 +1,7 @@ circuit Foo { f: u32, - function bar() -> u32 { + function bar(self) -> u32 { return self.f } } diff --git a/compiler/tests/mutability/circuit_static_function_mut.leo b/compiler/tests/mutability/circuit_static_function_mut.leo index 0717f51c44..eba1d02c0e 100644 --- a/compiler/tests/mutability/circuit_static_function_mut.leo +++ b/compiler/tests/mutability/circuit_static_function_mut.leo @@ -1,6 +1,6 @@ // Adding the `mut` keyword makes a circuit variable mutable. circuit Foo { - static function bar() {} + function bar() {} } function main() { diff --git a/compiler/tests/mutability/circuit_variable_mut.leo b/compiler/tests/mutability/circuit_variable_mut.leo index f87668c48e..27bd6109b2 100644 --- a/compiler/tests/mutability/circuit_variable_mut.leo +++ b/compiler/tests/mutability/circuit_variable_mut.leo @@ -1,6 +1,6 @@ // Adding the `mut` keyword makes a circuit variable mutable. circuit Foo { - mut x: u32 + x: u32 } function main() { diff --git a/compiler/tests/mutability/mod.rs b/compiler/tests/mutability/mod.rs index 8442357044..4da49d1765 100644 --- a/compiler/tests/mutability/mod.rs +++ b/compiler/tests/mutability/mod.rs @@ -78,7 +78,7 @@ fn test_circuit_mut() { let bytes = include_bytes!("circuit_mut.leo"); let program = parse_program(bytes).unwrap(); - expect_compiler_error(program); + assert_satisfied(program); } #[test] diff --git a/compiler/tests/syntax/mod.rs b/compiler/tests/syntax/mod.rs index 55b7292d2a..017d01a707 100644 --- a/compiler/tests/syntax/mod.rs +++ b/compiler/tests/syntax/mod.rs @@ -53,7 +53,7 @@ fn test_undefined() { " 2 | return a", " | ^", " |", - " = cannot find value `a` in this scope", + " = Cannot find value `a` in this scope", ] .join("\n") ); diff --git a/core/Cargo.toml b/core/Cargo.toml index f62744892d..e864dfbb6c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-core" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Core package dependencies of the Leo programming language" homepage = "https://aleo.org" @@ -19,11 +19,11 @@ edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-gadgets] path = "../gadgets" -version = "1.0.4" +version = "1.0.6" [dependencies.snarkos-errors] version = "1.1.3" diff --git a/core/src/packages/unstable/blake2s.rs b/core/src/packages/unstable/blake2s.rs index c4c37c4c91..22d8119e63 100644 --- a/core/src/packages/unstable/blake2s.rs +++ b/core/src/packages/unstable/blake2s.rs @@ -61,72 +61,69 @@ impl CoreCircuit for Blake2sCircuit { fn ast(circuit_name: Identifier, span: Span) -> Circuit { Circuit { circuit_name, - members: vec![CircuitMember::CircuitFunction( - true, // static function - Function { - identifier: Identifier { - name: "hash".to_owned(), + members: vec![CircuitMember::CircuitFunction(Function { + identifier: Identifier { + name: "hash".to_owned(), + span: span.clone(), + }, + input: vec![ + FunctionInput::Variable(FunctionInputVariable { + identifier: Identifier { + name: "seed".to_owned(), + span: span.clone(), + }, + mutable: false, + type_: Type::Array( + Box::new(Type::IntegerType(IntegerType::U8)), + ArrayDimensions(vec![PositiveNumber { + value: 32usize.to_string(), + span: span.clone(), + }]), + ), span: span.clone(), - }, - input: vec![ - FunctionInput::Variable(FunctionInputVariable { - identifier: Identifier { + }), + FunctionInput::Variable(FunctionInputVariable { + identifier: Identifier { + name: "message".to_owned(), + span: span.clone(), + }, + mutable: false, + type_: Type::Array( + Box::new(Type::IntegerType(IntegerType::U8)), + ArrayDimensions(vec![PositiveNumber { + value: 32usize.to_string(), + span: span.clone(), + }]), + ), + span: span.clone(), + }), + ], + output: Some(Type::Array( + Box::new(Type::IntegerType(IntegerType::U8)), + ArrayDimensions(vec![PositiveNumber { + value: 32usize.to_string(), + span: span.clone(), + }]), + )), + statements: vec![Statement::Return( + Expression::CoreFunctionCall( + Self::name(), + vec![ + Expression::Identifier(Identifier { name: "seed".to_owned(), span: span.clone(), - }, - mutable: false, - type_: Type::Array( - Box::new(Type::IntegerType(IntegerType::U8)), - ArrayDimensions(vec![PositiveNumber { - value: 32usize.to_string(), - span: span.clone(), - }]), - ), - span: span.clone(), - }), - FunctionInput::Variable(FunctionInputVariable { - identifier: Identifier { + }), + Expression::Identifier(Identifier { name: "message".to_owned(), span: span.clone(), - }, - mutable: false, - type_: Type::Array( - Box::new(Type::IntegerType(IntegerType::U8)), - ArrayDimensions(vec![PositiveNumber { - value: 32usize.to_string(), - span: span.clone(), - }]), - ), - span: span.clone(), - }), - ], - output: Some(Type::Array( - Box::new(Type::IntegerType(IntegerType::U8)), - ArrayDimensions(vec![PositiveNumber { - value: 32usize.to_string(), - span: span.clone(), - }]), - )), - statements: vec![Statement::Return( - Expression::CoreFunctionCall( - Self::name(), - vec![ - Expression::Identifier(Identifier { - name: "seed".to_owned(), - span: span.clone(), - }), - Expression::Identifier(Identifier { - name: "message".to_owned(), - span: span.clone(), - }), - ], - span.clone(), - ), + }), + ], span.clone(), - )], - span, - }, - )], + ), + span.clone(), + )], + span, + })], } } diff --git a/gadgets/Cargo.toml b/gadgets/Cargo.toml index de97fc34d0..650c5ee8ec 100644 --- a/gadgets/Cargo.toml +++ b/gadgets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-gadgets" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Gadgets of the Leo programming language" homepage = "https://aleo.org" diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index c33d877dba..3dec5aa9ed 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-grammar" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "AST generated by pest from the Leo grammar rules" homepage = "https://aleo.org" diff --git a/grammar/src/circuits/circuit_member.rs b/grammar/src/circuits/circuit_member.rs index d3d949e99b..32da1ca4d3 100644 --- a/grammar/src/circuits/circuit_member.rs +++ b/grammar/src/circuits/circuit_member.rs @@ -14,10 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - ast::Rule, - circuits::{CircuitFunction, CircuitVariableDefinition}, -}; +use crate::{ast::Rule, circuits::CircuitVariableDefinition, functions::Function}; use pest_ast::FromPest; use serde::Serialize; @@ -26,5 +23,5 @@ use serde::Serialize; #[pest_ast(rule(Rule::circuit_member))] pub enum CircuitMember<'ast> { CircuitVariableDefinition(CircuitVariableDefinition<'ast>), - CircuitFunction(CircuitFunction<'ast>), + CircuitFunction(Function<'ast>), } diff --git a/grammar/src/circuits/circuit_variable_definition.rs b/grammar/src/circuits/circuit_variable_definition.rs index 8bd462a099..b3a84ef629 100644 --- a/grammar/src/circuits/circuit_variable_definition.rs +++ b/grammar/src/circuits/circuit_variable_definition.rs @@ -14,12 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - ast::Rule, - common::{Identifier, Mutable}, - types::Type, - SpanDef, -}; +use crate::{ast::Rule, common::Identifier, types::Type, SpanDef}; use pest::Span; use pest_ast::FromPest; @@ -28,7 +23,6 @@ use serde::Serialize; #[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[pest_ast(rule(Rule::circuit_variable_definition))] pub struct CircuitVariableDefinition<'ast> { - pub mutable: Option, pub identifier: Identifier<'ast>, pub type_: Type<'ast>, #[pest_ast(outer())] diff --git a/grammar/src/circuits/mod.rs b/grammar/src/circuits/mod.rs index 768a36fd7e..c967ed655e 100644 --- a/grammar/src/circuits/mod.rs +++ b/grammar/src/circuits/mod.rs @@ -23,8 +23,5 @@ pub use circuit_variable::*; pub mod circuit_variable_definition; pub use circuit_variable_definition::*; -pub mod circuit_function; -pub use circuit_function::*; - pub mod circuit_member; pub use circuit_member::*; diff --git a/grammar/src/common/mod.rs b/grammar/src/common/mod.rs index 119287f5cc..6a45652fc7 100644 --- a/grammar/src/common/mod.rs +++ b/grammar/src/common/mod.rs @@ -35,6 +35,9 @@ pub use line_end::*; pub mod mutable; pub use mutable::*; +pub mod mut_self_keyword; +pub use mut_self_keyword::*; + pub mod range; pub use range::*; diff --git a/grammar/src/circuits/circuit_function.rs b/grammar/src/common/mut_self_keyword.rs similarity index 70% rename from grammar/src/circuits/circuit_function.rs rename to grammar/src/common/mut_self_keyword.rs index 3fdeac1d02..12d269e191 100644 --- a/grammar/src/circuits/circuit_function.rs +++ b/grammar/src/common/mut_self_keyword.rs @@ -14,18 +14,29 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ast::Rule, common::Static, functions::Function, SpanDef}; +use crate::{ + ast::Rule, + common::{Mutable, SelfKeyword}, + SpanDef, +}; use pest::Span; use pest_ast::FromPest; use serde::Serialize; +use std::fmt; #[derive(Clone, Debug, FromPest, PartialEq, Serialize)] -#[pest_ast(rule(Rule::circuit_function))] -pub struct CircuitFunction<'ast> { - pub _static: Option, - pub function: Function<'ast>, +#[pest_ast(rule(Rule::mut_self_keyword))] +pub struct MutSelfKeyword<'ast> { + pub mutable: Mutable, + pub self_keyword: SelfKeyword<'ast>, #[pest_ast(outer())] #[serde(with = "SpanDef")] pub span: Span<'ast>, } + +impl<'ast> fmt::Display for MutSelfKeyword<'ast> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "mut {}", self.self_keyword) + } +} diff --git a/grammar/src/functions/input/input.rs b/grammar/src/functions/input/input.rs index d3cddee215..d6eb28250c 100644 --- a/grammar/src/functions/input/input.rs +++ b/grammar/src/functions/input/input.rs @@ -16,6 +16,7 @@ use crate::{ ast::Rule, + common::{MutSelfKeyword, SelfKeyword}, functions::{FunctionInput, InputKeyword}, }; @@ -26,5 +27,7 @@ use serde::Serialize; #[pest_ast(rule(Rule::input))] pub enum Input<'ast> { InputKeyword(InputKeyword<'ast>), + SelfKeyword(SelfKeyword<'ast>), + MutSelfKeyword(MutSelfKeyword<'ast>), FunctionInput(FunctionInput<'ast>), } diff --git a/grammar/src/leo.pest b/grammar/src/leo.pest index e695e3bb9f..3879aa73f7 100644 --- a/grammar/src/leo.pest +++ b/grammar/src/leo.pest @@ -47,6 +47,9 @@ protected_name = { // Declared in common/self_keyword.rs self_keyword = { "self" } +// Declared in common/mut_self_keyword.rs +mut_self_keyword = { mutable ~ self_keyword } + // Declared in common/self_keyword_or_identifier.rs self_keyword_or_identifier = { self_keyword @@ -319,13 +322,10 @@ circuit = { "circuit " ~ identifier ~ "{" ~ NEWLINE* ~ circuit_member* ~ NEWLINE circuit_variable = { identifier ~ ":" ~ expression } // Declared in circuits/circuit_variable_definition.rs -circuit_variable_definition = { mutable? ~ identifier ~ ":" ~ type_ ~ ","?} - -// Declared in circuits/circuit_function.rs -circuit_function = { static_? ~ function } +circuit_variable_definition = { identifier ~ ":" ~ type_ ~ ","?} // Declared in circuits/circuit_member.rs -circuit_member = { circuit_function | circuit_variable_definition ~ NEWLINE*} +circuit_member = { function | circuit_variable_definition ~ NEWLINE*} /// Conditionals @@ -429,6 +429,8 @@ input_keyword = { "input" } // Declared in functions/input/input.rs input = { input_keyword + | self_keyword + | mut_self_keyword | function_input } input_tuple = _{ "(" ~ NEWLINE* ~ (input ~ ("," ~ NEWLINE* ~ input)* ~ ","?)? ~ NEWLINE* ~ ")"} diff --git a/imports/Cargo.toml b/imports/Cargo.toml index 691215fec6..3a4bd13771 100644 --- a/imports/Cargo.toml +++ b/imports/Cargo.toml @@ -1,32 +1,32 @@ [package] name = "leo-imports" -version = "1.0.4" -authors = [ "The Aleo Team "] +version = "1.0.6" +authors = [ "The Aleo Team " ] description = "Import parser for Leo program package dependencies" homepage = "https://aleo.org" repository = "https://github.com/AleoHQ/leo" keywords = [ - "aleo", - "cryptography", - "leo", - "programming-language", - "zero-knowledge" + "aleo", + "cryptography", + "leo", + "programming-language", + "zero-knowledge" ] categories = [ "cryptography::cryptocurrencies", "web-programming" ] -include = ["Cargo.toml", "src", "README.md", "LICENSE.md" ] +include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] license = "GPL-3.0" edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-grammar] path = "../grammar" -version = "1.0.4" +version = "1.0.6" [dependencies.thiserror] version = "1.0" [dependencies.tracing] -version = "0.1" \ No newline at end of file +version = "0.1" diff --git a/input/Cargo.toml b/input/Cargo.toml index 20003c5fb2..cb22145186 100644 --- a/input/Cargo.toml +++ b/input/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-input" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Input parser of the Leo programming language" homepage = "https://aleo.org" diff --git a/leo/leo-version b/leo/leo-version index 3b9e5dbc90..6df8b11430 100644 --- a/leo/leo-version +++ b/leo/leo-version @@ -1 +1 @@ -v1.0.4 \ No newline at end of file +v1.0.6 \ No newline at end of file diff --git a/linter/Cargo.toml b/linter/Cargo.toml index 8fafd81540..502578d2dc 100644 --- a/linter/Cargo.toml +++ b/linter/Cargo.toml @@ -2,7 +2,7 @@ dependencies = { } [package] name = "leo-linter" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Linter of the Leo programming language" homepage = "https://aleo.org" diff --git a/package/Cargo.toml b/package/Cargo.toml index dbe41fadbb..f1a1befb49 100644 --- a/package/Cargo.toml +++ b/package/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-package" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Package parser of the Leo programming language" homepage = "https://aleo.org" diff --git a/state/Cargo.toml b/state/Cargo.toml index 6f8b9063b7..e2a3f143ea 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-state" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "State parser of the Leo programming language" homepage = "https://aleo.org" @@ -19,11 +19,11 @@ edition = "2018" [dependencies.leo-input] path = "../input" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-ast] path = "../ast" -version = "1.0.4" +version = "1.0.6" [dependencies.snarkos-algorithms] version = "1.1.3" diff --git a/symbol-table/Cargo.toml b/symbol-table/Cargo.toml index 0e821fd122..809f0de36f 100644 --- a/symbol-table/Cargo.toml +++ b/symbol-table/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "leo-symbol-table" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Stores user-defined variables during type resolution" homepage = "https://aleo.org" repository = "https://github.com/AleoHQ/leo" keywords = [ - "aleo", - "cryptography", - "leo", - "programming-language", - "zero-knowledge" + "aleo", + "cryptography", + "leo", + "programming-language", + "zero-knowledge" ] categories = [ "cryptography::croptocurrencies", "web-programming" ] include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] @@ -19,22 +19,22 @@ edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-core] path = "../core" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-grammar] path = "../grammar" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-imports] path = "../imports" -version = "1.0.4" +version = "1.0.6" [dependencies.serde] version = "1.0" [dependencies.thiserror] -version = "1.0" \ No newline at end of file +version = "1.0" diff --git a/symbol-table/src/types/circuits/circuit.rs b/symbol-table/src/types/circuits/circuit.rs index 2e6ea923f0..df67e3495d 100644 --- a/symbol-table/src/types/circuits/circuit.rs +++ b/symbol-table/src/types/circuits/circuit.rs @@ -14,14 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - types::circuits::{CircuitFunctionType, CircuitVariableType}, - Attribute, - FunctionType, - SymbolTable, - Type, - TypeError, -}; +use crate::{types::circuits::CircuitVariableType, FunctionType, SymbolTable, Type, TypeError}; use leo_ast::{Circuit, CircuitMember, Identifier, InputValue, Parameter, Span}; use serde::{Deserialize, Serialize}; @@ -43,7 +36,7 @@ pub struct CircuitType { pub variables: Vec, /// The circuit functions. - pub functions: Vec, + pub functions: Vec, } impl CircuitType { @@ -61,7 +54,7 @@ impl CircuitType { // Resolve the type of every circuit member. for member in unresolved.members { match member { - CircuitMember::CircuitVariable(is_mutable, variable_identifier, type_) => { + CircuitMember::CircuitVariable(variable_identifier, type_) => { // Resolve the type of the circuit member variable. let type_ = Type::new_from_circuit( table, @@ -70,34 +63,22 @@ impl CircuitType { circuit_identifier.span.clone(), )?; - // Check if the circuit member variable is mutable. - let attribute = if is_mutable { Some(Attribute::Mutable) } else { None }; - // Create a new circuit variable type. let variable = CircuitVariableType { identifier: variable_identifier, type_, - attribute, + attribute: None, }; // Store the circuit variable type. variables.push(variable); } - CircuitMember::CircuitFunction(is_static, function) => { + CircuitMember::CircuitFunction(function) => { // Resolve the type of the circuit member function. let function_type = FunctionType::from_circuit(table, circuit_identifier.clone(), function)?; - // Check if the circuit member function is static. - let attribute = if is_static { Some(Attribute::Static) } else { None }; - - // Create a new circuit function type. - let function = CircuitFunctionType { - function: function_type, - attribute, - }; - // Store the circuit function type. - functions.push(function); + functions.push(function_type); } } } @@ -113,10 +94,10 @@ impl CircuitType { /// /// Returns the function type of a circuit member given an identifier. /// - pub fn member_function_type(&self, identifier: &Identifier) -> Option<&CircuitFunctionType> { + pub fn member_function_type(&self, identifier: &Identifier) -> Option<&FunctionType> { self.functions .iter() - .find(|function| function.function.identifier.eq(identifier)) + .find(|function| function.identifier.eq(identifier)) } /// @@ -139,7 +120,7 @@ impl CircuitType { let matched_function = self.member_function_type(identifier); match matched_function { - Some(function) => Ok(Type::Function(function.function.identifier.to_owned())), + Some(function) => Ok(Type::Function(function.identifier.to_owned())), None => Err(TypeError::undefined_circuit_member(identifier.clone())), } } diff --git a/symbol-table/src/types/circuits/mod.rs b/symbol-table/src/types/circuits/mod.rs index 8205016c50..5af76a09fe 100644 --- a/symbol-table/src/types/circuits/mod.rs +++ b/symbol-table/src/types/circuits/mod.rs @@ -17,8 +17,5 @@ pub mod circuit; pub use self::circuit::*; -pub mod circuit_function; -pub use self::circuit_function::*; - pub mod circuit_variable; pub use self::circuit_variable::*; diff --git a/symbol-table/src/types/functions/function.rs b/symbol-table/src/types/functions/function.rs index 0abdc87aa9..ffc35fde98 100644 --- a/symbol-table/src/types/functions/function.rs +++ b/symbol-table/src/types/functions/function.rs @@ -119,6 +119,34 @@ impl FunctionType { Ok(()) } + + /// + /// Returns the number of input variables to the function. + /// The `self` and `mut self` keywords are not counted as input variables. + /// + pub fn num_inputs(&self) -> usize { + self.inputs + .iter() + .fold(0, |acc, function_input| acc + function_input.count()) + } + + /// + /// Returns `true` if the input `self` or `mut self` is present. + /// Returns `false` otherwise. + /// + pub fn contains_self(&self) -> bool { + self.inputs.iter().any(|param| param.is_self()) + } + + /// + /// Returns a vector of [&FunctionInputType] removing `self` and `mut self` inputs. + /// + pub fn filter_self_inputs(&self) -> Vec<&FunctionInputType> { + self.inputs + .iter() + .filter(|input| !input.is_self()) + .collect::>() + } } impl PartialEq for FunctionType { diff --git a/symbol-table/src/types/functions/function_input.rs b/symbol-table/src/types/functions/function_input.rs index 297e09287f..66a8180f98 100644 --- a/symbol-table/src/types/functions/function_input.rs +++ b/symbol-table/src/types/functions/function_input.rs @@ -22,6 +22,8 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum FunctionInputType { InputKeyword(Identifier), + SelfKeyword(Identifier), + MutSelfKeyword(Identifier), Variable(FunctionInputVariableType), } @@ -32,6 +34,8 @@ impl FunctionInputType { pub fn identifier(&self) -> &Identifier { match self { FunctionInputType::InputKeyword(identifier) => identifier, + FunctionInputType::SelfKeyword(identifier) => identifier, + FunctionInputType::MutSelfKeyword(identifier) => identifier, FunctionInputType::Variable(variable) => &variable.identifier, } } @@ -42,6 +46,8 @@ impl FunctionInputType { pub fn type_(&self) -> Type { match self { FunctionInputType::InputKeyword(identifier) => Type::Circuit(identifier.to_owned()), + FunctionInputType::SelfKeyword(identifier) => Type::Circuit(identifier.to_owned()), + FunctionInputType::MutSelfKeyword(identifier) => Type::Circuit(identifier.to_owned()), FunctionInputType::Variable(variable) => variable.type_.to_owned(), } } @@ -52,10 +58,34 @@ impl FunctionInputType { pub fn span(&self) -> &Span { match self { FunctionInputType::InputKeyword(identifier) => &identifier.span, + FunctionInputType::SelfKeyword(identifier) => &identifier.span, + FunctionInputType::MutSelfKeyword(identifier) => &identifier.span, FunctionInputType::Variable(variable) => &variable.span, } } + /// + /// Returns `true` if input `self` or `mut self` is present. + /// Returns `false` otherwise. + /// + pub fn is_self(&self) -> bool { + match self { + FunctionInputType::InputKeyword(_) => false, + FunctionInputType::SelfKeyword(_) => true, + FunctionInputType::MutSelfKeyword(_) => true, + FunctionInputType::Variable(_) => false, + } + } + + /// + /// Returns `0` if the function input is a `self` or `mut self` keyword which does not have to + /// provided in a call to the function. + /// Returns `1` if a variable must be provided in a call to the function. + /// + pub fn count(&self) -> usize { + if self.is_self() { 0 } else { 1 } + } + /// /// Return a new `FunctionInputType` from a given `FunctionInput`. /// @@ -64,7 +94,9 @@ impl FunctionInputType { /// pub fn new(table: &SymbolTable, unresolved: FunctionInput) -> Result { Ok(match unresolved { - FunctionInput::InputKeyword(identifier) => FunctionInputType::InputKeyword(identifier), + FunctionInput::InputKeyword(keyword) => FunctionInputType::InputKeyword(Identifier::from(keyword)), + FunctionInput::SelfKeyword(_) => unimplemented!("cannot call self keyword from non-circuit context"), + FunctionInput::MutSelfKeyword(_) => unimplemented!("cannot call mut self keyword from non-circuit context"), FunctionInput::Variable(variable) => { let variable_resolved = FunctionInputVariableType::new(table, variable)?; @@ -88,7 +120,13 @@ impl FunctionInputType { circuit_name: Identifier, ) -> Result { Ok(match unresolved { - FunctionInput::InputKeyword(identifier) => FunctionInputType::InputKeyword(identifier), + FunctionInput::InputKeyword(keyword) => FunctionInputType::InputKeyword(Identifier::from(keyword)), + FunctionInput::SelfKeyword(keyword) => { + FunctionInputType::SelfKeyword(Identifier::new_with_span(&circuit_name.name, &keyword.span)) + } + FunctionInput::MutSelfKeyword(keyword) => { + FunctionInputType::MutSelfKeyword(Identifier::new_with_span(&circuit_name.name, &keyword.span)) + } FunctionInput::Variable(unresolved_function_input) => { let function_input = FunctionInputVariableType::new_from_circuit(table, unresolved_function_input, circuit_name)?; diff --git a/type-inference/Cargo.toml b/type-inference/Cargo.toml index a0f38f7418..4728d0e3d9 100644 --- a/type-inference/Cargo.toml +++ b/type-inference/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "leo-type-inference" -version = "1.0.4" +version = "1.0.6" authors = [ "The Aleo Team " ] description = "Checks that a program is correct using type inference" homepage = "https://aleo.org" repository = "https://github.com/AleoHQ/leo" keywords = [ - "aleo", - "cryptography", - "leo", - "programming-language", - "zero-knowledge" + "aleo", + "cryptography", + "leo", + "programming-language", + "zero-knowledge" ] categories = [ "cryptography::croptocurrencies", "web-programming" ] include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] @@ -19,19 +19,19 @@ edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-imports] path = "../imports" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-grammar] path = "../grammar" -version = "1.0.4" +version = "1.0.6" [dependencies.leo-symbol-table] path = "../symbol-table" -version = "1.0.4" +version = "1.0.6" [dependencies.serde_json] version = "1.0" @@ -40,4 +40,4 @@ version = "1.0" version = "1.0" [dependencies.thiserror] -version = "1.0" \ No newline at end of file +version = "1.0" diff --git a/type-inference/src/errors/frame.rs b/type-inference/src/errors/frame.rs index 36e8576832..814d2e8ff2 100644 --- a/type-inference/src/errors/frame.rs +++ b/type-inference/src/errors/frame.rs @@ -172,6 +172,27 @@ impl FrameError { Self::new_from_span(message, span) } + /// + /// The `self` keyword was used in a static circuit function signature. + /// + pub fn self_not_available(span: &Span) -> Self { + let message = "keyword `self` is only available in static circuit functions.".to_string(); + + Self::new_from_span(message, span) + } + + /// + /// A static function was accessed using dot `.` syntax instead of double colon `::` syntax. + /// + pub fn static_call_invalid(identifier: &Identifier) -> Self { + let message = format!( + "Static function `{}` must be called using double colon `::` syntax.", + identifier.name + ); + + Self::new_from_span(message, &identifier.span) + } + /// /// Attempted to access the index of a non-tuple type. /// diff --git a/type-inference/src/objects/frame.rs b/type-inference/src/objects/frame.rs index 6a455e61de..e725bff39b 100644 --- a/type-inference/src/objects/frame.rs +++ b/type-inference/src/objects/frame.rs @@ -34,7 +34,7 @@ use leo_ast::{ Statement, Variables, }; -use leo_symbol_table::{Attribute, CircuitFunctionType, CircuitType, FunctionType, SymbolTable, Type, TypeVariable}; +use leo_symbol_table::{CircuitType, FunctionType, SymbolTable, Type, TypeVariable}; /// A vector of `TypeAssertion` predicates created from a function body. #[derive(Clone)] @@ -100,13 +100,13 @@ impl Frame { let identifier = &function.identifier; // Find function name in circuit members. - let circuit_function_type = self_type.member_function_type(identifier).unwrap().to_owned(); + let function_type = self_type.member_function_type(identifier).unwrap().to_owned(); // Create a new scope for the function variables. let mut scope = Scope::new(Some(parent_scope)); // Initialize function inputs as variables. - scope.insert_function_inputs(&circuit_function_type.function.inputs)?; + scope.insert_function_inputs(&function_type.inputs)?; // Create new list of scopes for frame. let scopes = vec![scope]; @@ -114,7 +114,7 @@ impl Frame { // Create new frame struct. // Update variables when encountering let/const variable definitions. let mut frame = Self { - function_type: circuit_function_type.function, + function_type, self_type: Some(self_type), scopes, statements: function.statements, @@ -955,22 +955,6 @@ impl Frame { Ok(Type::Circuit(circuit_type.identifier)) } - /// - /// Returns the type of the accessed circuit member when called as an expression. - /// - fn parse_expression_circuit_member_access( - &mut self, - expression: &Expression, - identifier: &Identifier, - span: &Span, - ) -> Result { - // Parse circuit name. - let type_ = self.parse_expression(expression)?; - - // Parse the circuit member access. - self.parse_circuit_member_access(type_, identifier, span) - } - /// /// Returns the type of the accessed circuit member. /// @@ -987,6 +971,22 @@ impl Frame { Ok(circuit_type.member_type(&identifier)?) } + /// + /// Returns the type of the accessed circuit member when called as an expression. + /// + fn parse_expression_circuit_member_access( + &mut self, + expression: &Expression, + identifier: &Identifier, + span: &Span, + ) -> Result { + // Parse circuit name. + let type_ = self.parse_expression(expression)?; + + // Parse the circuit member access. + self.parse_circuit_member_access(type_, identifier, span) + } + /// /// Returns the type returned by calling the static circuit function. /// @@ -1029,10 +1029,10 @@ impl Frame { match expression { Expression::Identifier(identifier) => self.parse_program_function(identifier, span), Expression::CircuitMemberAccess(expression, identifier, span) => { - self.parse_circuit_function(expression, identifier, span) + self.parse_circuit_function(expression, identifier, span, false) } Expression::CircuitStaticFunctionAccess(expression, identifier, span) => { - self.parse_static_circuit_function(expression, identifier, span) + self.parse_circuit_function(expression, identifier, span, true) } expression => Err(FrameError::invalid_function(expression, span)), } @@ -1056,7 +1056,7 @@ impl Frame { expression: &Expression, identifier: &Identifier, span: &Span, - ) -> Result<&CircuitFunctionType, FrameError> { + ) -> Result<&FunctionType, FrameError> { // Parse circuit name. let type_ = self.parse_expression(expression)?; @@ -1077,37 +1077,25 @@ impl Frame { expression: &Expression, identifier: &Identifier, span: &Span, + is_static: bool, ) -> Result { // Find circuit function type. - let circuit_function_type = self.parse_circuit_function_type(expression, identifier, span)?; + let function_type = self.parse_circuit_function_type(expression, identifier, span)?; - // Check that the function is non-static. - if let Some(Attribute::Static) = circuit_function_type.attribute { - return Err(FrameError::invalid_static_access(identifier)); + // Case 1: static call + self keyword => Error + // Case 2: no static call + no self keywords => Error + // Case 3: static call + no self keywords => Ok + // Case 4: no static call + self keyword => Ok + if is_static && function_type.contains_self() { + return Err(FrameError::self_not_available(&identifier.span)); + } else if !is_static && !function_type.contains_self() { + return Err(FrameError::static_call_invalid(&identifier)); } + if is_static && function_type.contains_self() {} + // Return the function type. - Ok(circuit_function_type.function.to_owned()) - } - - /// - /// Returns a `FunctionType` given a circuit expression and static function identifier. - /// - fn parse_static_circuit_function( - &mut self, - expression: &Expression, - identifier: &Identifier, - span: &Span, - ) -> Result { - // Find circuit function type. - let circuit_function_type = self.parse_circuit_function_type(expression, identifier, span)?; - - // Check that the function is static. - if let Some(Attribute::Static) = circuit_function_type.attribute { - Ok(circuit_function_type.function.to_owned()) - } else { - Err(FrameError::invalid_member_access(identifier)) - } + Ok(function_type.to_owned()) } /// @@ -1125,12 +1113,17 @@ impl Frame { let function_type = self.parse_function_name(expression, span)?; // Check the length of arguments - if function_type.inputs.len() != inputs.len() { - return Err(FrameError::num_inputs(function_type.inputs.len(), inputs.len(), span)); + let num_inputs = function_type.num_inputs(); + + if num_inputs != inputs.len() { + return Err(FrameError::num_inputs(num_inputs, inputs.len(), span)); } + // Filter out `self` and `mut self` keywords. + let expected_inputs = function_type.filter_self_inputs(); + // Assert function inputs are correct types. - for (expected_input, actual_input) in function_type.inputs.iter().zip(inputs) { + for (expected_input, actual_input) in expected_inputs.iter().zip(inputs) { // Parse expected input type. let expected_type = expected_input.type_(); diff --git a/type-inference/src/type_inference.rs b/type-inference/src/type_inference.rs index fee87bb035..17baf6db4c 100644 --- a/type-inference/src/type_inference.rs +++ b/type-inference/src/type_inference.rs @@ -82,7 +82,7 @@ impl TypeInference { // Create a new function for each circuit member function. for circuit_member in &circuit.members { // ignore circuit member variables - if let CircuitMember::CircuitFunction(_, function) = circuit_member { + if let CircuitMember::CircuitFunction(function) = circuit_member { // Collect `TypeAssertion` predicates from the function. // Pass down circuit self type and circuit variable types to each function. let frame = Frame::new_circuit_function(