implement group::GEN Leo syntax (#2401)

* implement group::GEN Leo syntax

* revert unrelated test changes

* move new errors to bottom of file to keep previous error codes consistent
This commit is contained in:
Collin Chin 2023-05-31 16:05:56 -07:00 committed by GitHub
parent 369db97edd
commit 42d97d3d89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 155 additions and 9 deletions

View File

@ -0,0 +1,41 @@
// Copyright (C) 2019-2023 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::Type;
use leo_span::{sym, Symbol};
/// A core constant that maps directly to an AVM bytecode constant.
#[derive(Clone, PartialEq, Eq)]
pub enum CoreConstant {
GroupGenerator,
}
impl CoreConstant {
/// Returns a `CoreConstant` from the given type and constant symbols.
pub fn from_symbols(type_: Symbol, constant: Symbol) -> Option<Self> {
Some(match (type_, constant) {
(sym::group, sym::GEN) => Self::GroupGenerator,
_ => return None,
})
}
/// Returns the `Type` of the `CoreConstant`.
pub fn to_type(&self) -> Type {
match self {
Self::GroupGenerator => Type::Group,
}
}
}

View File

@ -13,6 +13,8 @@
// 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/>.
pub mod core_constant;
pub use core_constant::*;
pub mod integer_type;
pub use integer_type::*;

View File

@ -17,6 +17,7 @@
use crate::CodeGenerator;
use leo_ast::{
AccessExpression,
AssociatedConstant,
AssociatedFunction,
BinaryExpression,
BinaryOperation,
@ -233,6 +234,11 @@ impl<'a> CodeGenerator<'a> {
(member_access_instruction, String::new())
}
// group::GEN -> group::GEN
fn visit_associated_constant(&mut self, input: &'a AssociatedConstant) -> (String, String) {
(format!("{input}"), String::new())
}
// Pedersen64::hash() -> hash.ped64
fn visit_associated_function(&mut self, input: &'a AssociatedFunction) -> (String, String) {
let mut instructions = String::new();
@ -337,7 +343,7 @@ impl<'a> CodeGenerator<'a> {
fn visit_access(&mut self, input: &'a AccessExpression) -> (String, String) {
match input {
AccessExpression::Member(access) => self.visit_member_access(access),
AccessExpression::AssociatedConstant(_) => todo!(), // Associated constants are not supported in AVM yet.
AccessExpression::AssociatedConstant(constant) => self.visit_associated_constant(constant),
AccessExpression::AssociatedFunction(function) => self.visit_associated_function(function),
AccessExpression::Tuple(_) => todo!(), // Tuples are not supported in AVM yet.
}

View File

@ -150,7 +150,19 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
}
}
AccessExpression::AssociatedConstant(..) => {} // todo: Add support for associated constants (u8::MAX).
AccessExpression::AssociatedConstant(access) => {
// Check associated constant type and constant name
if let Some(core_constant) = self.get_core_constant(&access.ty, &access.name) {
// Check return type if the expected type is known.
let return_type = Some(core_constant.to_type());
if let Some(expected) = expected {
self.assert_type(&return_type, expected, input.span());
}
return return_type;
} else {
self.emit_err(TypeCheckerError::invalid_associated_constant(access, access.span))
}
}
}
None
}

View File

@ -16,7 +16,7 @@
use crate::{CallGraph, StructGraph, SymbolTable};
use leo_ast::{CoreFunction, Identifier, IntegerType, MappingType, Node, Type, Variant};
use leo_ast::{CoreConstant, CoreFunction, Identifier, IntegerType, MappingType, Node, Type, Variant};
use leo_errors::{emitter::Handler, TypeCheckerError};
use leo_span::{Span, Symbol};
@ -302,6 +302,21 @@ impl<'a> TypeChecker<'a> {
)
}
/// Type checks the inputs to an associated constant and returns the expected output type.
pub(crate) fn get_core_constant(&self, type_: &Type, constant: &Identifier) -> Option<CoreConstant> {
if let Type::Identifier(ident) = type_ {
// Lookup core constant
match CoreConstant::from_symbols(ident.name, constant.name) {
None => {
// Not a core constant.
self.emit_err(TypeCheckerError::invalid_core_constant(ident.name, constant.name, ident.span()));
}
Some(core_constant) => return Some(core_constant),
}
}
None
}
/// Emits an error if the `struct` is not a core library struct.
/// Emits an error if the `function` is not supported by the struct.
pub(crate) fn get_core_function_call(&self, struct_: &Type, function: &Identifier) -> Option<CoreFunction> {

View File

@ -141,6 +141,9 @@ symbols! {
sub_wrapped,
xor,
// core constants
GEN,
// core functions
BHP256,
BHP512,

View File

@ -163,7 +163,7 @@ create_messages!(
help: None,
}
/// An invalid access call is made e.g., `bool::MAX`
/// An invalid access call is made e.g., `SHA256::hash()
@formatted
invalid_core_function_call {
args: (expr: impl Display),
@ -594,11 +594,30 @@ create_messages!(
msg: format!("A finalize block cannot return a value."),
help: None,
}
@formatted
too_many_mappings {
args: (max: impl Display),
msg: format!("The number of mappings exceeds the maximum. snarkVM allows up to {max} mappings within a single program."),
help: None,
}
/// A call to an invalid associated constant is made e.g., `bool::MAX`
@formatted
invalid_associated_constant {
args: (expr: impl Display),
msg: format!(
"{expr} is not a valid associated constant."
),
help: None,
}
/// For when an invalid core constant is called.
@formatted
invalid_core_constant {
args: (type_: impl Display, constant: impl Display),
msg: format! (
"{type_}::{constant} is not a valid core constant.",
),
help: None,
}
);

View File

@ -4,13 +4,16 @@ program groups.aleo {
transition main(a: group) -> group {
// unary
let e: group = a.double(); // 2a
let g: group = e.neg(); // -2a
let b: group = a.double(); // 2a
let c: group = b.neg(); // -2a
// binary
let j: group = (a * 2scalar).add(g);
let d: group = (a * 2scalar).add(c);
return j;
// generator
let e: group = group::GEN;
return d + e;
}
}

View File

@ -0,0 +1,12 @@
---
namespace: Compile
expectation: Pass
outputs:
- - initial_ast: fad70d5af8fae67cf7c511f82d51bbb417bc16c2b082d987d775284981be49bc
unrolled_ast: fad70d5af8fae67cf7c511f82d51bbb417bc16c2b082d987d775284981be49bc
ssa_ast: 29b1770e006849d42def40fd2291158a0cd21e9db3ecd03bd6bdfdcc6eb43e0a
flattened_ast: 64556dacc04129ffd9f1f68074266e924b5804440aaaeb152a8a33b6fbc80228
inlined_ast: 64556dacc04129ffd9f1f68074266e924b5804440aaaeb152a8a33b6fbc80228
dce_ast: 64556dacc04129ffd9f1f68074266e924b5804440aaaeb152a8a33b6fbc80228
bytecode: cd542f776048c64f42b745a4be5ebe93fe7a8638c8d1692d3d774d491cadfe45
warnings: ""

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372074]: group::GENERATOR is not a valid core constant.\n --> compiler-test:7:24\n |\n 7 | let a: group = group::GENERATOR;\n | ^^^^^\nError [ETYC0372073]: group::GENERATOR is not a valid associated constant.\n --> compiler-test:7:24\n |\n 7 | let a: group = group::GENERATOR;\n | ^^^^^^^^^^^^^^^^\n"

View File

@ -0,0 +1,14 @@
/*
namespace: Compile
expectation: Pass
*/
program test.aleo {
transition main(
group_value: group,
) -> group {
let a: group = group::GEN;
return group_value + a;
}
}

View File

@ -0,0 +1,14 @@
/*
namespace: Compile
expectation: Fail
*/
program test.aleo {
transition main(
group_value: group,
) -> group {
let a: group = group::GENERATOR;
return group_value + a;
}
}