mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 18:21:38 +03:00
Tyc for mappings
This commit is contained in:
parent
1b6dea395f
commit
8a8e198f59
33
compiler/ast/src/types/mapping.rs
Normal file
33
compiler/ast/src/types/mapping.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2019-2022 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 serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A mapping type of a key and value type.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct MappingType {
|
||||
pub key: Box<Type>,
|
||||
pub value: Box<Type>,
|
||||
}
|
||||
|
||||
impl fmt::Display for MappingType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({} => {})", self.key, self.value)
|
||||
}
|
||||
}
|
@ -17,6 +17,9 @@
|
||||
pub mod integer_type;
|
||||
pub use integer_type::*;
|
||||
|
||||
pub mod mapping;
|
||||
pub use mapping::*;
|
||||
|
||||
pub mod tuple;
|
||||
pub use tuple::*;
|
||||
|
||||
|
@ -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::{Identifier, IntegerType, Tuple};
|
||||
use crate::{Identifier, IntegerType, MappingType, Tuple};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@ -35,6 +35,8 @@ pub enum Type {
|
||||
Identifier(Identifier),
|
||||
/// An integer type.
|
||||
Integer(IntegerType),
|
||||
/// A mapping type.
|
||||
Mapping(MappingType),
|
||||
/// The `scalar` type.
|
||||
Scalar,
|
||||
/// The `string` type.
|
||||
@ -61,6 +63,9 @@ impl Type {
|
||||
| (Type::Scalar, Type::Scalar)
|
||||
| (Type::String, Type::String) => true,
|
||||
(Type::Integer(left), Type::Integer(right)) => left.eq(right),
|
||||
(Type::Mapping(left), Type::Mapping(right)) => {
|
||||
left.key.eq_flat(&right.key) && left.value.eq_flat(&right.value)
|
||||
}
|
||||
(Type::Tuple(left), Type::Tuple(right)) => left
|
||||
.iter()
|
||||
.zip(right.iter())
|
||||
@ -80,6 +85,7 @@ impl fmt::Display for Type {
|
||||
Type::Group => write!(f, "group"),
|
||||
Type::Identifier(ref variable) => write!(f, "{}", variable),
|
||||
Type::Integer(ref integer_type) => write!(f, "{}", integer_type),
|
||||
Type::Mapping(ref mapping_type) => write!(f, "{}", mapping_type),
|
||||
Type::Scalar => write!(f, "scalar"),
|
||||
Type::String => write!(f, "string"),
|
||||
Type::Tuple(ref tuple) => write!(f, "{}", tuple),
|
||||
|
@ -36,8 +36,11 @@ impl<'a> CodeGenerator<'a> {
|
||||
unreachable!("All composite types should be known at this phase of compilation")
|
||||
}
|
||||
}
|
||||
Type::Mapping(_) => {
|
||||
unreachable!("Mapping types are not supported at this phase of compilation")
|
||||
}
|
||||
Type::Tuple(_) => {
|
||||
unreachable!("All composite types should be known at this phase of compilation")
|
||||
unreachable!("Tuple types are not supported at this phase of compilation")
|
||||
}
|
||||
Type::Err => unreachable!("Error types should not exist at this phase of compilation"),
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use leo_ast::*;
|
||||
use leo_errors::emitter::Handler;
|
||||
|
||||
use crate::SymbolTable;
|
||||
use crate::{SymbolTable, VariableSymbol, VariableType};
|
||||
|
||||
/// A compiler pass during which the `SymbolTable` is created.
|
||||
/// Note that this pass only creates the initial entries for functions and circuits.
|
||||
@ -58,6 +58,23 @@ impl<'a> ProgramVisitor<'a> for CreateSymbolTable<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mapping(&mut self, input: &'a Mapping) {
|
||||
// Add the variable associated with the mapping to the symbol table.
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
input.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: Type::Mapping(MappingType {
|
||||
key: Box::new(input.key_type.clone()),
|
||||
value: Box::new(input.value_type.clone()),
|
||||
}),
|
||||
span: input.span,
|
||||
declaration: VariableType::Mut,
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_import(&mut self, input: &'a Program) {
|
||||
self.visit_program(input)
|
||||
}
|
||||
|
@ -147,4 +147,22 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
self.assert_member_is_not_record(v.span, input.identifier.name, type_);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mapping(&mut self, input: &'a Mapping) {
|
||||
// Check that a mapping's key type is not tuple types or mapping types.
|
||||
match input.key_type {
|
||||
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("key", "tuple", input.span)),
|
||||
// Note that this is not possible since the parser does not currently accept mapping types.
|
||||
Type::Mapping(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("key", "mapping", input.span)),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Check that a mapping's value type is not tuple types or mapping types.
|
||||
match input.value_type {
|
||||
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("value", "tuple", input.span)),
|
||||
// Note that this is not possible since the parser does not currently accept mapping types.
|
||||
Type::Mapping(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("value", "mapping", input.span)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,4 +295,11 @@ create_messages!(
|
||||
msg: format!("A circuit or record cannot contain another record."),
|
||||
help: Some(format!("Remove the record `{child}` from `{parent}`.")),
|
||||
}
|
||||
|
||||
@formatted
|
||||
invalid_mapping_type {
|
||||
args: (component: impl Display, type_: impl Display),
|
||||
msg: format!("A mapping's {component} cannot be a {type_}"),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
13
tests/compiler/mapping/simple_mapping.leo
Normal file
13
tests/compiler/mapping/simple_mapping.leo
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
*/
|
||||
|
||||
mapping balances: address => u128;
|
||||
|
||||
circuit Token {
|
||||
owner: address;
|
||||
balance: u128;
|
||||
}
|
||||
|
||||
mapping tokens: address => Token;
|
6
tests/compiler/mapping/tuple_mapping_fail.leo
Normal file
6
tests/compiler/mapping/tuple_mapping_fail.leo
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
*/
|
||||
|
||||
mapping foo: (u32, u32) => u32;
|
9
tests/expectations/compiler/mapping/simple_mapping.out
Normal file
9
tests/expectations/compiler/mapping/simple_mapping.out
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: no input
|
||||
initial_ast: 40dc8ad2ebf4af78e20722af3a6772e22254724fe566e4c7232949c87f010813
|
||||
unrolled_ast: 40dc8ad2ebf4af78e20722af3a6772e22254724fe566e4c7232949c87f010813
|
||||
ssa_ast: 40dc8ad2ebf4af78e20722af3a6772e22254724fe566e4c7232949c87f010813
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372031]: A mapping's key cannot be a tuple\n --> compiler-test:3:1\n |\n 3 | mapping foo: (u32, u32) => u32;\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
|
Loading…
Reference in New Issue
Block a user