impl tuple type expression

This commit is contained in:
collin 2022-07-09 10:15:08 -07:00
parent a1c42a8d3f
commit 296c62a280
12 changed files with 424 additions and 309 deletions

View File

@ -38,7 +38,7 @@ impl fmt::Display for CircuitVariableInitializer {
/// A circuit initialization expression, e.g., `Foo { bar: 42, baz }`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CircuitInitExpression {
pub struct CircuitExpression {
/// The name of the structure type to initialize.
pub name: Identifier,
/// Initializer expressions for each of the fields in the circuit.
@ -50,7 +50,7 @@ pub struct CircuitInitExpression {
pub span: Span,
}
impl fmt::Display for CircuitInitExpression {
impl fmt::Display for CircuitExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {{ ", self.name)?;
for member in self.members.iter() {
@ -61,4 +61,4 @@ impl fmt::Display for CircuitInitExpression {
}
}
crate::simple_node_impl!(CircuitInitExpression);
crate::simple_node_impl!(CircuitExpression);

View File

@ -38,6 +38,9 @@ pub use err::*;
mod ternary;
pub use ternary::*;
mod tuple_init;
pub use tuple_init::*;
mod unary;
pub use unary::*;
@ -49,21 +52,23 @@ pub use value::*;
pub enum Expression {
/// A circuit access expression, e.g., `Foo.bar`.
Access(AccessExpression),
/// An identifier expression.
Identifier(Identifier),
/// A literal expression.
Literal(LiteralExpression),
/// A binary expression, e.g., `42 + 24`.
Binary(BinaryExpression),
/// A call expression, e.g., `my_fun(args)`.
Call(CallExpression),
/// An expression constructing a circuit like `Foo { bar: 42, baz }`.
CircuitInit(CircuitInitExpression),
Circuit(CircuitExpression),
/// An expression of type "error".
/// Will result in a compile error eventually.
Err(ErrExpression),
/// An identifier.
Identifier(Identifier),
/// A literal expression.
Literal(LiteralExpression),
/// A ternary conditional expression `cond ? if_expr : else_expr`.
Ternary(TernaryExpression),
/// A tuple expression e.g., `(foo, 42, true)`.
Tuple(TupleExpression),
/// An unary expression.
Unary(UnaryExpression),
}
@ -73,13 +78,14 @@ impl Node for Expression {
use Expression::*;
match self {
Access(n) => n.span(),
Identifier(n) => n.span(),
Literal(n) => n.span(),
Binary(n) => n.span(),
Call(n) => n.span(),
CircuitInit(n) => n.span(),
Circuit(n) => n.span(),
Err(n) => n.span(),
Identifier(n) => n.span(),
Literal(n) => n.span(),
Ternary(n) => n.span(),
Tuple(n) => n.span(),
Unary(n) => n.span(),
}
}
@ -88,13 +94,14 @@ impl Node for Expression {
use Expression::*;
match self {
Access(n) => n.set_span(span),
Identifier(n) => n.set_span(span),
Literal(n) => n.set_span(span),
Binary(n) => n.set_span(span),
Call(n) => n.set_span(span),
CircuitInit(n) => n.set_span(span),
Circuit(n) => n.set_span(span),
Identifier(n) => n.set_span(span),
Literal(n) => n.set_span(span),
Err(n) => n.set_span(span),
Ternary(n) => n.set_span(span),
Tuple(n) => n.set_span(span),
Unary(n) => n.set_span(span),
}
}
@ -105,13 +112,14 @@ impl fmt::Display for Expression {
use Expression::*;
match &self {
Access(n) => n.fmt(f),
Identifier(n) => n.fmt(f),
Literal(n) => n.fmt(f),
Binary(n) => n.fmt(f),
Call(n) => n.fmt(f),
CircuitInit(n) => n.fmt(f),
Circuit(n) => n.fmt(f),
Err(n) => n.fmt(f),
Identifier(n) => n.fmt(f),
Literal(n) => n.fmt(f),
Ternary(n) => n.fmt(f),
Tuple(n) => n.fmt(f),
Unary(n) => n.fmt(f),
}
}

View File

@ -0,0 +1,43 @@
// 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 super::*;
/// A tuple construction expression, e.g., `(foo, false, 42)`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TupleExpression {
/// The elements of the tuple.
/// In the example above, it would be `foo`, `false`, and `42`.
pub elements: Vec<Expression>,
/// The span from `(` to `)`.
pub span: Span,
}
impl fmt::Display for TupleExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"({})",
self.elements
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(",")
)
}
}
crate::simple_node_impl!(TupleExpression);

View File

@ -27,33 +27,22 @@ pub trait ExpressionReconstructor {
fn reconstruct_expression(&mut self, input: Expression) -> (Expression, Self::AdditionalOutput) {
match input {
Expression::Access(access) => self.reconstruct_access(access),
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
Expression::Literal(value) => self.reconstruct_literal(value),
Expression::Binary(binary) => self.reconstruct_binary(binary),
Expression::Call(call) => self.reconstruct_call(call),
Expression::CircuitInit(circuit) => self.reconstruct_circuit_init(circuit),
Expression::Unary(unary) => self.reconstruct_unary(unary),
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
Expression::Circuit(circuit) => self.reconstruct_circuit_init(circuit),
Expression::Err(err) => self.reconstruct_err(err),
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
Expression::Literal(value) => self.reconstruct_literal(value),
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
Expression::Tuple(tuple) => self.reconstruct_tuple(tuple),
Expression::Unary(unary) => self.reconstruct_unary(unary),
}
}
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
(Expression::Identifier(input), Default::default())
}
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Literal(input), Default::default())
}
fn reconstruct_access(&mut self, input: AccessExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Access(input), Default::default())
}
fn reconstruct_circuit_init(&mut self, input: CircuitInitExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::CircuitInit(input), Default::default())
}
fn reconstruct_binary(&mut self, input: BinaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Binary(BinaryExpression {
@ -66,28 +55,6 @@ pub trait ExpressionReconstructor {
)
}
fn reconstruct_unary(&mut self, input: UnaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Unary(UnaryExpression {
receiver: Box::new(self.reconstruct_expression(*input.receiver).0),
op: input.op,
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Ternary(TernaryExpression {
condition: Box::new(self.reconstruct_expression(*input.condition).0),
if_true: Box::new(self.reconstruct_expression(*input.if_true).0),
if_false: Box::new(self.reconstruct_expression(*input.if_false).0),
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
(
@ -104,9 +71,58 @@ pub trait ExpressionReconstructor {
)
}
fn reconstruct_circuit_init(&mut self, input: CircuitExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Circuit(input), Default::default())
}
fn reconstruct_err(&mut self, input: ErrExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Err(input), Default::default())
}
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
(Expression::Identifier(input), Default::default())
}
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
(Expression::Literal(input), Default::default())
}
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Ternary(TernaryExpression {
condition: Box::new(self.reconstruct_expression(*input.condition).0),
if_true: Box::new(self.reconstruct_expression(*input.if_true).0),
if_false: Box::new(self.reconstruct_expression(*input.if_false).0),
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_tuple(&mut self, input: TupleExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Tuple(TupleExpression {
elements: input
.elements
.into_iter()
.map(|element| self.reconstruct_expression(element).0)
.collect(),
span: input.span,
}),
Default::default(),
)
}
fn reconstruct_unary(&mut self, input: UnaryExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Unary(UnaryExpression {
receiver: Box::new(self.reconstruct_expression(*input.receiver).0),
op: input.op,
span: input.span,
}),
Default::default(),
)
}
}
/// A Reconstructor trait for statements in the AST.

View File

@ -27,15 +27,16 @@ pub trait ExpressionVisitor<'a> {
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Self::Output {
match input {
Expression::Access(expr) => self.visit_access(expr, additional),
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
Expression::Literal(expr) => self.visit_literal(expr, additional),
Expression::Binary(expr) => self.visit_binary(expr, additional),
Expression::Unary(expr) => self.visit_unary(expr, additional),
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
Expression::Call(expr) => self.visit_call(expr, additional),
Expression::Err(expr) => self.visit_err(expr, additional),
Expression::Access(access) => self.visit_access(access, additional),
Expression::Binary(binary) => self.visit_binary(binary, additional),
Expression::Call(call) => self.visit_call(call, additional),
Expression::Circuit(circuit) => self.visit_circuit_init(circuit, additional),
Expression::Err(err) => self.visit_err(err, additional),
Expression::Identifier(identifier) => self.visit_identifier(identifier, additional),
Expression::Literal(literal) => self.visit_literal(literal, additional),
Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
Expression::Unary(unary) => self.visit_unary(unary, additional),
}
}
@ -43,40 +44,12 @@ pub trait ExpressionVisitor<'a> {
Default::default()
}
fn visit_circuit_init(
&mut self,
_input: &'a CircuitInitExpression,
_additional: &Self::AdditionalInput,
) -> Self::Output {
Default::default()
}
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_binary(&mut self, input: &'a BinaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.left, additional);
self.visit_expression(&input.right, additional);
Default::default()
}
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.receiver, additional);
Default::default()
}
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, additional);
self.visit_expression(&input.if_true, additional);
self.visit_expression(&input.if_false, additional);
Default::default()
}
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Self::Output {
input.arguments.iter().for_each(|expr| {
self.visit_expression(expr, additional);
@ -87,6 +60,40 @@ pub trait ExpressionVisitor<'a> {
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
Default::default()
}
fn visit_circuit_init(
&mut self,
_input: &'a CircuitExpression,
_additional: &Self::AdditionalInput,
) -> Self::Output {
Default::default()
}
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, additional);
self.visit_expression(&input.if_true, additional);
self.visit_expression(&input.if_false, additional);
Default::default()
}
fn visit_tuple(&mut self, input: &'a TupleExpression, additional: &Self::AdditionalInput) -> Self::Output {
input.elements.iter().for_each(|expr| {
self.visit_expression(expr, additional);
});
Default::default()
}
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.receiver, additional);
Default::default()
}
}
/// A Visitor trait for statements in the AST.

View File

@ -19,10 +19,7 @@ use leo_errors::{AstError, Result};
use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::{
fmt,
ops::Deref
};
use std::{fmt, ops::Deref};
/// A type list of at least two types.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -34,7 +31,7 @@ impl Tuple {
match elements.len() {
0 => Err(AstError::empty_tuple(span).into()),
1 => Err(AstError::one_element_tuple(span).into()),
_ => Ok(Type::Tuple(Tuple(elements)))
_ => Ok(Type::Tuple(Tuple(elements))),
}
}
}
@ -49,6 +46,10 @@ impl Deref for Tuple {
impl fmt::Display for Tuple {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({})", self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))
write!(
f,
"({})",
self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
)
}
}
}

View File

@ -470,7 +470,7 @@ impl ParserContext<'_> {
p.parse_circuit_member().map(Some)
})?;
Ok(Expression::CircuitInit(CircuitInitExpression {
Ok(Expression::Circuit(CircuitExpression {
span: identifier.span + end,
name: identifier,
members,

View File

@ -43,14 +43,15 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
fn visit_expression(&mut self, input: &'a Expression, expected: &Self::AdditionalInput) -> Self::Output {
match input {
Expression::Access(expr) => self.visit_access(expr, expected),
Expression::Identifier(expr) => self.visit_identifier(expr, expected),
Expression::Literal(expr) => self.visit_literal(expr, expected),
Expression::Binary(expr) => self.visit_binary(expr, expected),
Expression::Call(expr) => self.visit_call(expr, expected),
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, expected),
Expression::Err(expr) => self.visit_err(expr, expected),
Expression::Ternary(expr) => self.visit_ternary(expr, expected),
Expression::Access(access) => self.visit_access(access, expected),
Expression::Binary(binary) => self.visit_binary(binary, expected),
Expression::Call(call) => self.visit_call(call, expected),
Expression::Circuit(circuit) => self.visit_circuit_init(circuit, expected),
Expression::Identifier(identifier) => self.visit_identifier(identifier, expected),
Expression::Err(err) => self.visit_err(err, expected),
Expression::Literal(literal) => self.visit_literal(literal, expected),
Expression::Ternary(ternary) => self.visit_ternary(ternary, expected),
Expression::Tuple(tuple) => self.visit_tuple(tuple, expected),
Expression::Unary(expr) => self.visit_unary(expr, expected),
}
}
@ -97,155 +98,6 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
}
fn visit_circuit_init(
&mut self,
input: &'a CircuitInitExpression,
additional: &Self::AdditionalInput,
) -> Self::Output {
let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned();
if let Some(circ) = circ {
// Check circuit type name.
let ret = self.check_expected_circuit(circ.identifier, additional, input.name.span());
// Check number of circuit members.
if circ.members.len() != input.members.len() {
self.handler.emit_err(
TypeCheckerError::incorrect_num_circuit_members(
circ.members.len(),
input.members.len(),
input.span(),
)
.into(),
);
}
// Check circuit member types.
circ.members
.iter()
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
// Lookup circuit variable name.
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
if let Some(expr) = &actual.expression {
self.visit_expression(expr, &Some(ty.clone()));
}
} else {
self.handler.emit_err(
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
);
};
});
Some(ret)
} else {
self.handler
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
None
}
}
fn visit_identifier(&mut self, var: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
if let Some(circuit) = self.symbol_table.borrow().lookup_circuit(&var.name) {
Some(self.assert_and_return_type(Type::Identifier(circuit.identifier), expected, var.span))
} else if let Some(var) = self.symbol_table.borrow().lookup_variable(&var.name) {
Some(self.assert_and_return_type(var.type_.clone(), expected, var.span))
} else {
self.handler
.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()).into());
None
}
}
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
Some(match input {
LiteralExpression::Address(_, _) => self.assert_and_return_type(Type::Address, expected, input.span()),
LiteralExpression::Boolean(_, _) => self.assert_and_return_type(Type::Boolean, expected, input.span()),
LiteralExpression::Field(_, _) => self.assert_and_return_type(Type::Field, expected, input.span()),
LiteralExpression::Integer(type_, str_content, _) => {
match type_ {
IntegerType::I8 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i8>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()).into());
}
}
IntegerType::I16 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i16>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()).into());
}
}
IntegerType::I32 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i32>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()).into());
}
}
IntegerType::I64 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i64>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()).into());
}
}
IntegerType::I128 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i128>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()).into());
}
}
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()).into()),
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()).into()),
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()).into()),
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()).into()),
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
_ => {}
}
self.assert_and_return_type(Type::IntegerType(*type_), expected, input.span())
}
LiteralExpression::Group(_) => self.assert_and_return_type(Type::Group, expected, input.span()),
LiteralExpression::Scalar(_, _) => self.assert_and_return_type(Type::Scalar, expected, input.span()),
LiteralExpression::String(_, _) => self.assert_and_return_type(Type::String, expected, input.span()),
})
}
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
match input.op {
@ -470,6 +322,228 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
}
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
match &*input.function {
Expression::Identifier(ident) => {
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
if let Some(func) = func {
let ret = self.assert_and_return_type(func.output, expected, func.span);
// Check number of function arguments.
if func.input.len() != input.arguments.len() {
self.handler.emit_err(
TypeCheckerError::incorrect_num_args_to_call(
func.input.len(),
input.arguments.len(),
input.span(),
)
.into(),
);
}
// Check function argument types.
func.input
.iter()
.zip(input.arguments.iter())
.for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.get_variable().type_.clone()));
});
Some(ret)
} else {
self.handler
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
None
}
}
expr => self.visit_expression(expr, expected),
}
}
fn visit_circuit_init(
&mut self,
input: &'a CircuitExpression,
additional: &Self::AdditionalInput,
) -> Self::Output {
let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned();
if let Some(circ) = circ {
// Check circuit type name.
let ret = self.check_expected_circuit(circ.identifier, additional, input.name.span());
// Check number of circuit members.
if circ.members.len() != input.members.len() {
self.emit_err(
TypeCheckerError::incorrect_num_circuit_members(
circ.members.len(),
input.members.len(),
input.span(),
)
.into(),
);
}
// Check circuit member types.
circ.members
.iter()
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
// Lookup circuit variable name.
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
if let Some(expr) = &actual.expression {
self.visit_expression(expr, &Some(ty.clone()));
}
} else {
self.handler.emit_err(
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
);
};
});
Some(ret)
} else {
self.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
None
}
}
fn visit_identifier(&mut self, var: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
if let Some(circuit) = self.symbol_table.borrow().lookup_circuit(&var.name) {
Some(self.assert_and_return_type(Type::Identifier(circuit.identifier), expected, var.span))
} else if let Some(var) = self.symbol_table.borrow().lookup_variable(&var.name) {
Some(self.assert_and_return_type(var.type_.clone(), expected, var.span))
} else {
self.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()).into());
None
}
}
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
Some(match input {
LiteralExpression::Address(_, _) => self.assert_and_return_type(Type::Address, expected, input.span()),
LiteralExpression::Boolean(_, _) => self.assert_and_return_type(Type::Boolean, expected, input.span()),
LiteralExpression::Field(_, _) => self.assert_and_return_type(Type::Field, expected, input.span()),
LiteralExpression::Integer(type_, str_content, _) => {
match type_ {
IntegerType::I8 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i8>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()).into());
}
}
IntegerType::I16 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i16>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()).into());
}
}
IntegerType::I32 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i32>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()).into());
}
}
IntegerType::I64 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i64>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()).into());
}
}
IntegerType::I128 => {
let int = if self.negate {
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i128>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()).into());
}
}
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()).into()),
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()).into()),
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()).into()),
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()).into()),
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
_ => {}
}
self.assert_and_return_type(Type::IntegerType(*type_), expected, input.span())
}
LiteralExpression::Group(_) => self.assert_and_return_type(Type::Group, expected, input.span()),
LiteralExpression::Scalar(_, _) => self.assert_and_return_type(Type::Scalar, expected, input.span()),
LiteralExpression::String(_, _) => self.assert_and_return_type(Type::String, expected, input.span()),
})
}
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, &Some(Type::Boolean));
let t1 = self.visit_expression(&input.if_true, expected);
let t2 = self.visit_expression(&input.if_false, expected);
return_incorrect_type(t1, t2, expected)
}
fn visit_tuple(&mut self, input: &'a TupleExpression, expected: &Self::AdditionalInput) -> Self::Output {
// Check the expected tuple types if they are known.
if let Some(Type::Tuple(expected_types)) = expected {
// Check actual length is equal to expected length.
if expected_types.len() != input.elements.len() {
self.emit_err(TypeCheckerError::incorrect_tuple_length(expected_types.len(), input.elements.len(), input.span()));
}
expected_types
.iter()
.zip(input.elements.iter())
.for_each(|(expected, expr)| {
self.visit_expression(expr, &Some(expected.clone()));
});
Some(Type::Tuple(expected_types.clone()))
} else {
// Tuples must be explicitly typed in testnet3.
self.emit_err(TypeCheckerError::invalid_tuple(input.span()));
None
}
}
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
match input.op {
UnaryOperation::Abs => {
@ -521,50 +595,4 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
}
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, &Some(Type::Boolean));
let t1 = self.visit_expression(&input.if_true, expected);
let t2 = self.visit_expression(&input.if_false, expected);
return_incorrect_type(t1, t2, expected)
}
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
match &*input.function {
Expression::Identifier(ident) => {
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
if let Some(func) = func {
let ret = self.assert_and_return_type(func.output, expected, func.span);
// Check number of function arguments.
if func.input.len() != input.arguments.len() {
self.handler.emit_err(
TypeCheckerError::incorrect_num_args_to_call(
func.input.len(),
input.arguments.len(),
input.span(),
)
.into(),
);
}
// Check function argument types.
func.input
.iter()
.zip(input.arguments.iter())
.for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.get_variable().type_.clone()));
});
Some(ret)
} else {
self.handler
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
None
}
}
expr => self.visit_expression(expr, expected),
}
}
}

View File

@ -52,8 +52,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
self.visit_block(&input.block);
if !self.has_return {
self.handler
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
self.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
}
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();

View File

@ -83,8 +83,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
Some(var.type_.clone())
} else {
self.handler
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
self.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
None
};

View File

@ -85,7 +85,7 @@ impl<'a> TypeChecker<'a> {
}
/// Emits a type checker error.
fn emit_err(&self, err: TypeCheckerError) {
pub fn emit_err(&self, err: TypeCheckerError) {
self.handler.emit_err(err.into());
}

View File

@ -271,4 +271,18 @@ create_messages!(
msg: format!("Comparison `{operator}` is not supported for the address type."),
help: None,
}
@formatted
incorrect_tuple_length {
args: (expected: impl Display, actual: impl Display),
msg: format!("Expected a tuple of length `{expected}` got `{actual}`"),
help: None,
}
@formatted
invalid_tuple {
args: (),
msg: format!("Tuples must be explicitly typed in Leo"),
help: Some("The function definition must match the function return statement".to_string()),
}
);