mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 18:21:38 +03:00
clean up and fix type set checking
This commit is contained in:
parent
d0273719ab
commit
eee58883a6
@ -34,7 +34,7 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
|
||||
}
|
||||
|
||||
pub fn reduce_type(&mut self, type_: &Type, span: &Span) -> Result<Type> {
|
||||
self.reducer.reduce_type(type_, type_.clone(), span)
|
||||
self.reducer.reduce_type(type_, *type_, span)
|
||||
}
|
||||
|
||||
// Expressions
|
||||
|
@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// Explicit type used for defining a variable or expression type
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Type {
|
||||
// Data types
|
||||
/// The `address` type.
|
||||
@ -51,12 +51,12 @@ impl Type {
|
||||
///
|
||||
pub fn eq_flat(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Type::Address, Type::Address) => true,
|
||||
(Type::Boolean, Type::Boolean) => true,
|
||||
(Type::Field, Type::Field) => true,
|
||||
(Type::Group, Type::Group) => true,
|
||||
(Type::Char, Type::Char) => true,
|
||||
(Type::Scalar, Type::Scalar) => true,
|
||||
(Type::Address, Type::Address)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Field, Type::Field)
|
||||
| (Type::Group, Type::Group)
|
||||
| (Type::Char, Type::Char)
|
||||
| (Type::Scalar, Type::Scalar) => true,
|
||||
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ impl<'a> TypeChecker<'a> {
|
||||
match expr {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(var) = self.symbol_table.lookup_variable(&ident.name) {
|
||||
Some(self.assert_type(var.type_.clone(), expected, span))
|
||||
Some(self.assert_type(*var.type_, expected, span))
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", ident.name, span).into());
|
||||
@ -148,28 +148,28 @@ impl<'a> TypeChecker<'a> {
|
||||
},
|
||||
Expression::Binary(binary) => match binary.op {
|
||||
BinaryOperation::And | BinaryOperation::Or => {
|
||||
self.assert_type(Type::Boolean, expected.clone(), binary.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected.clone(), binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span());
|
||||
self.assert_type(Type::Boolean, expected, binary.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
|
||||
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
BinaryOperation::Add => {
|
||||
self.assert_field_group_scalar_int_type(expected.clone(), binary.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected.clone(), binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span());
|
||||
self.assert_field_group_scalar_int_type(expected, binary.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
|
||||
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
BinaryOperation::Sub => {
|
||||
self.assert_field_group_int_type(expected.clone(), binary.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected.clone(), binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span());
|
||||
self.assert_field_group_int_type(expected, binary.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
|
||||
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
BinaryOperation::Mul => {
|
||||
self.assert_field_group_int_type(expected.clone(), binary.span());
|
||||
self.assert_field_group_int_type(expected, binary.span());
|
||||
|
||||
let t1 = self.compare_expr_type(&binary.left, None, binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, None, binary.right.span());
|
||||
@ -177,17 +177,17 @@ impl<'a> TypeChecker<'a> {
|
||||
// Allow `group` * `scalar` multiplication.
|
||||
match (t1.as_ref(), t2.as_ref()) {
|
||||
(Some(Type::Group), Some(other)) | (Some(other), Some(Type::Group)) => {
|
||||
self.assert_type(other.clone(), Some(Type::Scalar), binary.span());
|
||||
self.assert_type(*other, Some(Type::Scalar), binary.span());
|
||||
Some(Type::Group)
|
||||
}
|
||||
_ => return_incorrect_type(t1, t2, expected),
|
||||
}
|
||||
}
|
||||
BinaryOperation::Div => {
|
||||
self.assert_field_int_type(expected.clone(), binary.span());
|
||||
self.assert_field_int_type(expected, binary.span());
|
||||
|
||||
let t1 = self.compare_expr_type(&binary.left, expected.clone(), binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span());
|
||||
let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
BinaryOperation::Pow => {
|
||||
@ -198,7 +198,7 @@ impl<'a> TypeChecker<'a> {
|
||||
// Type A must be an int.
|
||||
// Type B must be a unsigned int.
|
||||
(Some(Type::IntegerType(_)), Some(Type::IntegerType(itype))) if !itype.is_signed() => {
|
||||
self.assert_type(t1.clone().unwrap(), expected, binary.span());
|
||||
self.assert_type(t1.unwrap(), expected, binary.span());
|
||||
}
|
||||
// Type A was an int.
|
||||
// But Type B was not a unsigned int.
|
||||
@ -231,7 +231,7 @@ impl<'a> TypeChecker<'a> {
|
||||
t1
|
||||
}
|
||||
BinaryOperation::Eq | BinaryOperation::Ne => {
|
||||
self.assert_type(Type::Boolean, expected.clone(), binary.span());
|
||||
self.assert_type(Type::Boolean, expected, binary.span());
|
||||
|
||||
let t1 = self.compare_expr_type(&binary.left, None, binary.left.span());
|
||||
let t2 = self.compare_expr_type(&binary.right, None, binary.right.span());
|
||||
@ -239,20 +239,20 @@ impl<'a> TypeChecker<'a> {
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Le | BinaryOperation::Ge => {
|
||||
self.assert_type(Type::Boolean, expected.clone(), binary.span());
|
||||
self.assert_type(Type::Boolean, expected, binary.span());
|
||||
|
||||
let t1 = self.compare_expr_type(&binary.left, None, binary.left.span());
|
||||
self.assert_field_scalar_int_type(t1.clone(), binary.left.span());
|
||||
self.assert_field_scalar_int_type(t1, binary.left.span());
|
||||
|
||||
let t2 = self.compare_expr_type(&binary.right, None, binary.right.span());
|
||||
self.assert_field_scalar_int_type(t2.clone(), binary.right.span());
|
||||
self.assert_field_scalar_int_type(t2, binary.right.span());
|
||||
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
},
|
||||
Expression::Unary(unary) => match unary.op {
|
||||
UnaryOperation::Not => {
|
||||
self.assert_type(Type::Boolean, expected.clone(), unary.span());
|
||||
self.assert_type(Type::Boolean, expected, unary.span());
|
||||
self.compare_expr_type(&unary.inner, expected, unary.inner.span())
|
||||
}
|
||||
UnaryOperation::Negate => {
|
||||
@ -278,14 +278,14 @@ impl<'a> TypeChecker<'a> {
|
||||
},
|
||||
Expression::Ternary(ternary) => {
|
||||
self.compare_expr_type(&ternary.condition, Some(Type::Boolean), ternary.condition.span());
|
||||
let t1 = self.compare_expr_type(&ternary.if_true, expected.clone(), ternary.if_true.span());
|
||||
let t2 = self.compare_expr_type(&ternary.if_false, expected.clone(), ternary.if_false.span());
|
||||
let t1 = self.compare_expr_type(&ternary.if_true, expected, ternary.if_true.span());
|
||||
let t2 = self.compare_expr_type(&ternary.if_false, expected, ternary.if_false.span());
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
Expression::Call(call) => match &*call.function {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(func) = self.symbol_table.lookup_fn(&ident.name) {
|
||||
let ret = self.assert_type(func.output.clone(), expected, ident.span());
|
||||
let ret = self.assert_type(func.output, expected, ident.span());
|
||||
|
||||
if func.input.len() != call.arguments.len() {
|
||||
self.handler.emit_err(
|
||||
@ -302,11 +302,7 @@ impl<'a> TypeChecker<'a> {
|
||||
.iter()
|
||||
.zip(call.arguments.iter())
|
||||
.for_each(|(expected, argument)| {
|
||||
self.compare_expr_type(
|
||||
argument,
|
||||
Some(expected.get_variable().type_.clone()),
|
||||
argument.span(),
|
||||
);
|
||||
self.compare_expr_type(argument, Some(expected.get_variable().type_), argument.span());
|
||||
});
|
||||
|
||||
Some(ret)
|
||||
|
@ -26,7 +26,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
let parent = self.parent.unwrap();
|
||||
|
||||
// Would never be None.
|
||||
let func_output_type = self.symbol_table.lookup_fn(&parent).map(|f| f.output.clone());
|
||||
let func_output_type = self.symbol_table.lookup_fn(&parent).map(|f| f.output);
|
||||
self.compare_expr_type(&input.expression, func_output_type, input.expression.span());
|
||||
|
||||
VisitResult::VisitChildren
|
||||
@ -51,7 +51,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
self.compare_expr_type(&input.value, Some(input.type_.clone()), input.value.span());
|
||||
self.compare_expr_type(&input.value, Some(input.type_), input.value.span());
|
||||
});
|
||||
|
||||
VisitResult::VisitChildren
|
||||
@ -70,7 +70,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Some(var.type_.clone())
|
||||
Some(*var.type_)
|
||||
} else {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("variable", &input.assignee.identifier.name, input.assignee.span).into(),
|
||||
@ -104,8 +104,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
self.compare_expr_type(&input.start, Some(input.type_.clone()), input.start.span());
|
||||
self.compare_expr_type(&input.stop, Some(input.type_.clone()), input.stop.span());
|
||||
self.compare_expr_type(&input.start, Some(input.type_), input.start.span());
|
||||
self.compare_expr_type(&input.stop, Some(input.type_), input.stop.span());
|
||||
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
|
@ -27,9 +27,6 @@ pub struct TypeChecker<'a> {
|
||||
pub(crate) negate: bool,
|
||||
}
|
||||
|
||||
const FIELD_TYPE: Type = Type::Field;
|
||||
const GROUP_TYPE: Type = Type::Group;
|
||||
const SCALAR_TYPE: Type = Type::Scalar;
|
||||
const INT_TYPES: [Type; 10] = [
|
||||
Type::IntegerType(IntegerType::I8),
|
||||
Type::IntegerType(IntegerType::I16),
|
||||
@ -43,6 +40,32 @@ const INT_TYPES: [Type; 10] = [
|
||||
Type::IntegerType(IntegerType::U128),
|
||||
];
|
||||
|
||||
const fn create_type_superset<const S: usize, const A: usize, const O: usize>(
|
||||
subset: [Type; S],
|
||||
additional: [Type; A],
|
||||
) -> [Type; O] {
|
||||
let mut superset: [Type; O] = [Type::IntegerType(IntegerType::U8); O];
|
||||
let mut i = 0;
|
||||
while i < S {
|
||||
superset[i] = subset[i];
|
||||
i += 1;
|
||||
}
|
||||
let mut j = 0;
|
||||
while j < A {
|
||||
superset[i + j] = additional[j];
|
||||
j += 1;
|
||||
}
|
||||
superset
|
||||
}
|
||||
|
||||
const FIELD_INT_TYPES: [Type; 11] = create_type_superset(INT_TYPES, [Type::Field]);
|
||||
|
||||
const FIELD_SCALAR_INT_TYPES: [Type; 12] = create_type_superset(FIELD_INT_TYPES, [Type::Scalar]);
|
||||
|
||||
const FIELD_GROUP_INT_TYPES: [Type; 12] = create_type_superset(FIELD_INT_TYPES, [Type::Group]);
|
||||
|
||||
const ALL_NUMERICAL_TYPES: [Type; 13] = create_type_superset(FIELD_GROUP_INT_TYPES, [Type::Scalar]);
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
pub fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
|
||||
Self {
|
||||
@ -57,7 +80,7 @@ impl<'a> TypeChecker<'a> {
|
||||
if let Some(expected) = expected {
|
||||
if type_ != expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(type_.clone(), expected, span).into());
|
||||
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into());
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +88,7 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn assert_one_of_types(&self, type_: Option<Type>, expected: &[Type], span: Span) -> Option<Type> {
|
||||
if let Some(type_) = type_.clone() {
|
||||
if let Some(type_) = type_ {
|
||||
for t in expected.iter() {
|
||||
if &type_ == t {
|
||||
return Some(type_);
|
||||
@ -85,23 +108,31 @@ impl<'a> TypeChecker<'a> {
|
||||
type_
|
||||
}
|
||||
|
||||
pub(crate) fn _assert_arith_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_INT_TYPES, span)
|
||||
}
|
||||
|
||||
pub(crate) fn _assert_field_or_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
|
||||
}
|
||||
|
||||
pub(crate) fn _assert_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, &INT_TYPES, span)
|
||||
}
|
||||
|
||||
pub(crate) fn assert_field_group_scalar_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, , span)
|
||||
self.assert_one_of_types(type_, &ALL_NUMERICAL_TYPES, span)
|
||||
}
|
||||
|
||||
pub(crate) fn assert_field_group_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, , span)
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_INT_TYPES, span)
|
||||
}
|
||||
|
||||
pub(crate) fn assert_field_scalar_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, , span)
|
||||
self.assert_one_of_types(type_, &FIELD_SCALAR_INT_TYPES, span)
|
||||
}
|
||||
|
||||
pub(crate) fn assert_field_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, span)
|
||||
}
|
||||
|
||||
pub(crate) fn assert_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
|
||||
self.assert_one_of_types(type_, , span)
|
||||
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
|
||||
}
|
||||
}
|
||||
|
8
tests/expectations/compiler/compiler/scalar/cmp.leo.out
Normal file
8
tests/expectations/compiler/compiler/scalar/cmp.leo.out
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: 85349bd16d49ff31c5ed3aeacf84ee6278d4d951409f8b055849eb41481e612e
|
||||
initial_ast: f9d6d5d94f9aead249bf86205884b49eff222937842973864758c01757d3eafa
|
||||
symbol_table: 240729bf3dd32b0ff548d132bc74bc91e42a8677f98d5fa1e388259e6a407d95
|
Loading…
Reference in New Issue
Block a user