clean up and fix type set checking

This commit is contained in:
gluax 2022-05-23 11:07:43 -07:00
parent d0273719ab
commit eee58883a6
6 changed files with 90 additions and 55 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 85349bd16d49ff31c5ed3aeacf84ee6278d4d951409f8b055849eb41481e612e
initial_ast: f9d6d5d94f9aead249bf86205884b49eff222937842973864758c01757d3eafa
symbol_table: 240729bf3dd32b0ff548d132bc74bc91e42a8677f98d5fa1e388259e6a407d95