Tyc for mappings

This commit is contained in:
Pranav Gaddamadugu 2022-08-25 10:33:00 -07:00
parent 1b6dea395f
commit 8a8e198f59
11 changed files with 123 additions and 3 deletions

View 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)
}
}

View File

@ -17,6 +17,9 @@
pub mod integer_type;
pub use integer_type::*;
pub mod mapping;
pub use mapping::*;
pub mod tuple;
pub use tuple::*;

View File

@ -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),

View File

@ -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"),
}

View File

@ -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)
}

View File

@ -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)),
_ => {}
}
}
}

View File

@ -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,
}
);

View File

@ -0,0 +1,13 @@
/*
namespace: Compile
expectation: Pass
*/
mapping balances: address => u128;
circuit Token {
owner: address;
balance: u128;
}
mapping tokens: address => Token;

View File

@ -0,0 +1,6 @@
/*
namespace: Compile
expectation: Fail
*/
mapping foo: (u32, u32) => u32;

View 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

View File

@ -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"