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> { 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 // Expressions

View File

@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
/// Explicit type used for defining a variable or expression type /// 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 { pub enum Type {
// Data types // Data types
/// The `address` type. /// The `address` type.
@ -51,12 +51,12 @@ impl Type {
/// ///
pub fn eq_flat(&self, other: &Self) -> bool { pub fn eq_flat(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Type::Address, Type::Address) => true, (Type::Address, Type::Address)
(Type::Boolean, Type::Boolean) => true, | (Type::Boolean, Type::Boolean)
(Type::Field, Type::Field) => true, | (Type::Field, Type::Field)
(Type::Group, Type::Group) => true, | (Type::Group, Type::Group)
(Type::Char, Type::Char) => true, | (Type::Char, Type::Char)
(Type::Scalar, Type::Scalar) => true, | (Type::Scalar, Type::Scalar) => true,
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right), (Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right),
_ => false, _ => false,
} }

View File

@ -43,7 +43,7 @@ impl<'a> TypeChecker<'a> {
match expr { match expr {
Expression::Identifier(ident) => { Expression::Identifier(ident) => {
if let Some(var) = self.symbol_table.lookup_variable(&ident.name) { 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 { } else {
self.handler self.handler
.emit_err(TypeCheckerError::unknown_sym("variable", ident.name, span).into()); .emit_err(TypeCheckerError::unknown_sym("variable", ident.name, span).into());
@ -148,28 +148,28 @@ impl<'a> TypeChecker<'a> {
}, },
Expression::Binary(binary) => match binary.op { Expression::Binary(binary) => match binary.op {
BinaryOperation::And | BinaryOperation::Or => { BinaryOperation::And | BinaryOperation::Or => {
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, expected.clone(), binary.left.span()); let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span()); let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
return_incorrect_type(t1, t2, expected) return_incorrect_type(t1, t2, expected)
} }
BinaryOperation::Add => { BinaryOperation::Add => {
self.assert_field_group_scalar_int_type(expected.clone(), binary.span()); self.assert_field_group_scalar_int_type(expected, binary.span());
let t1 = self.compare_expr_type(&binary.left, expected.clone(), binary.left.span()); let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span()); let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
return_incorrect_type(t1, t2, expected) return_incorrect_type(t1, t2, expected)
} }
BinaryOperation::Sub => { BinaryOperation::Sub => {
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, expected.clone(), binary.left.span()); let t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span()); let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
return_incorrect_type(t1, t2, expected) return_incorrect_type(t1, t2, expected)
} }
BinaryOperation::Mul => { 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 t1 = self.compare_expr_type(&binary.left, None, binary.left.span());
let t2 = self.compare_expr_type(&binary.right, None, binary.right.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. // Allow `group` * `scalar` multiplication.
match (t1.as_ref(), t2.as_ref()) { match (t1.as_ref(), t2.as_ref()) {
(Some(Type::Group), Some(other)) | (Some(other), Some(Type::Group)) => { (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) Some(Type::Group)
} }
_ => return_incorrect_type(t1, t2, expected), _ => return_incorrect_type(t1, t2, expected),
} }
} }
BinaryOperation::Div => { 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 t1 = self.compare_expr_type(&binary.left, expected, binary.left.span());
let t2 = self.compare_expr_type(&binary.right, expected.clone(), binary.right.span()); let t2 = self.compare_expr_type(&binary.right, expected, binary.right.span());
return_incorrect_type(t1, t2, expected) return_incorrect_type(t1, t2, expected)
} }
BinaryOperation::Pow => { BinaryOperation::Pow => {
@ -198,7 +198,7 @@ impl<'a> TypeChecker<'a> {
// Type A must be an int. // Type A must be an int.
// Type B must be a unsigned int. // Type B must be a unsigned int.
(Some(Type::IntegerType(_)), Some(Type::IntegerType(itype))) if !itype.is_signed() => { (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. // Type A was an int.
// But Type B was not a unsigned int. // But Type B was not a unsigned int.
@ -231,7 +231,7 @@ impl<'a> TypeChecker<'a> {
t1 t1
} }
BinaryOperation::Eq | BinaryOperation::Ne => { 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 t1 = self.compare_expr_type(&binary.left, None, binary.left.span());
let t2 = self.compare_expr_type(&binary.right, None, binary.right.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) return_incorrect_type(t1, t2, expected)
} }
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Le | BinaryOperation::Ge => { 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()); 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()); 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) return_incorrect_type(t1, t2, expected)
} }
}, },
Expression::Unary(unary) => match unary.op { Expression::Unary(unary) => match unary.op {
UnaryOperation::Not => { 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()) self.compare_expr_type(&unary.inner, expected, unary.inner.span())
} }
UnaryOperation::Negate => { UnaryOperation::Negate => {
@ -278,14 +278,14 @@ impl<'a> TypeChecker<'a> {
}, },
Expression::Ternary(ternary) => { Expression::Ternary(ternary) => {
self.compare_expr_type(&ternary.condition, Some(Type::Boolean), ternary.condition.span()); 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 t1 = self.compare_expr_type(&ternary.if_true, expected, ternary.if_true.span());
let t2 = self.compare_expr_type(&ternary.if_false, expected.clone(), ternary.if_false.span()); let t2 = self.compare_expr_type(&ternary.if_false, expected, ternary.if_false.span());
return_incorrect_type(t1, t2, expected) return_incorrect_type(t1, t2, expected)
} }
Expression::Call(call) => match &*call.function { Expression::Call(call) => match &*call.function {
Expression::Identifier(ident) => { Expression::Identifier(ident) => {
if let Some(func) = self.symbol_table.lookup_fn(&ident.name) { 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() { if func.input.len() != call.arguments.len() {
self.handler.emit_err( self.handler.emit_err(
@ -302,11 +302,7 @@ impl<'a> TypeChecker<'a> {
.iter() .iter()
.zip(call.arguments.iter()) .zip(call.arguments.iter())
.for_each(|(expected, argument)| { .for_each(|(expected, argument)| {
self.compare_expr_type( self.compare_expr_type(argument, Some(expected.get_variable().type_), argument.span());
argument,
Some(expected.get_variable().type_.clone()),
argument.span(),
);
}); });
Some(ret) Some(ret)

View File

@ -26,7 +26,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
let parent = self.parent.unwrap(); let parent = self.parent.unwrap();
// Would never be None. // 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()); self.compare_expr_type(&input.expression, func_output_type, input.expression.span());
VisitResult::VisitChildren VisitResult::VisitChildren
@ -51,7 +51,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
self.handler.emit_err(err); 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 VisitResult::VisitChildren
@ -70,7 +70,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
_ => {} _ => {}
} }
Some(var.type_.clone()) Some(*var.type_)
} else { } else {
self.handler.emit_err( self.handler.emit_err(
TypeCheckerError::unknown_sym("variable", &input.assignee.identifier.name, input.assignee.span).into(), 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.handler.emit_err(err);
} }
self.compare_expr_type(&input.start, Some(input.type_.clone()), input.start.span()); self.compare_expr_type(&input.start, Some(input.type_), input.start.span());
self.compare_expr_type(&input.stop, Some(input.type_.clone()), input.stop.span()); self.compare_expr_type(&input.stop, Some(input.type_), input.stop.span());
VisitResult::VisitChildren VisitResult::VisitChildren
} }

View File

@ -27,9 +27,6 @@ pub struct TypeChecker<'a> {
pub(crate) negate: bool, 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] = [ const INT_TYPES: [Type; 10] = [
Type::IntegerType(IntegerType::I8), Type::IntegerType(IntegerType::I8),
Type::IntegerType(IntegerType::I16), Type::IntegerType(IntegerType::I16),
@ -43,6 +40,32 @@ const INT_TYPES: [Type; 10] = [
Type::IntegerType(IntegerType::U128), 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> { impl<'a> TypeChecker<'a> {
pub fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self { pub fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
Self { Self {
@ -57,7 +80,7 @@ impl<'a> TypeChecker<'a> {
if let Some(expected) = expected { if let Some(expected) = expected {
if type_ != expected { if type_ != expected {
self.handler 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> { 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() { for t in expected.iter() {
if &type_ == t { if &type_ == t {
return Some(type_); return Some(type_);
@ -85,23 +108,31 @@ impl<'a> TypeChecker<'a> {
type_ 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> { 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> { 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> { 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> { pub(crate) fn assert_field_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)
}
pub(crate) fn assert_int_type(&self, type_: Option<Type>, span: Span) -> Option<Type> {
self.assert_one_of_types(type_, , span)
} }
} }

View File

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