From 605f675ff612f0cd49e18223fe8eafd1c0f641db Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Tue, 27 Sep 2022 13:34:27 -0700 Subject: [PATCH] More tyc --- .../src/type_checking/check_expressions.rs | 11 ++-- .../passes/src/type_checking/check_program.rs | 50 ++++++++++++------- .../src/type_checking/check_statements.rs | 19 +++---- compiler/passes/src/type_checking/checker.rs | 26 ++++++++-- .../errors/type_checker/type_checker_error.rs | 8 +-- 5 files changed, 72 insertions(+), 42 deletions(-) diff --git a/compiler/passes/src/type_checking/check_expressions.rs b/compiler/passes/src/type_checking/check_expressions.rs index a9cf9c44b7..46ba5e68e1 100644 --- a/compiler/passes/src/type_checking/check_expressions.rs +++ b/compiler/passes/src/type_checking/check_expressions.rs @@ -650,11 +650,16 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> { fn visit_tuple(&mut self, input: &'a TupleExpression, expected: &Self::AdditionalInput) -> Self::Output { match input.elements.len() { - 0 => Some(self.assert_and_return_type(Type::Unit, expected, input.span())), - 1 => self.visit_expression(&input.elements[0], expected), + 0 => { + self.emit_err(TypeCheckerError::unit_tuple(input.span())); + None + } + 1 => { + self.emit_err(TypeCheckerError::singleton_tuple(input.span())); + None + } _ => { // 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() { diff --git a/compiler/passes/src/type_checking/check_program.rs b/compiler/passes/src/type_checking/check_program.rs index fb6a718a6b..4de05892a1 100644 --- a/compiler/passes/src/type_checking/check_program.rs +++ b/compiler/passes/src/type_checking/check_program.rs @@ -24,17 +24,23 @@ use leo_span::sym; use std::collections::HashSet; // TODO: Generally, cleanup tyc logic. +// TODO: Cleanup logic for tuples. impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { fn visit_struct(&mut self, input: &'a Struct) { // Check for conflicting struct/record member names. let mut used = HashSet::new(); - if !input.members.iter().all(|Member { identifier, type_ }| { - // TODO: Better spans. - // Check that the member types are valid. - self.assert_type_is_valid(input.span, type_); - used.insert(identifier.name) - }) { + if !input + .members + .iter() + .all(|Member { identifier, type_} | { + // TODO: Better spans. + // Check that the member types are valid. + self.assert_type_is_defined(type_, ident.span); + self.assert_valid_declaration_or_parameter_type(type_, ident.span); + used.insert(ident.name) + }) + { self.emit_err(if input.is_record { TypeCheckerError::duplicate_record_variable(input.name(), input.span()) } else { @@ -79,7 +85,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { fn visit_mapping(&mut self, input: &'a Mapping) { // Check that a mapping's key type is valid. - self.assert_type_is_valid(input.span, &input.key_type); + self.assert_type_is_defined(&input.key_type, input.span); // 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)), @@ -89,7 +95,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { } // Check that a mapping's value type is valid. - self.assert_type_is_valid(input.span, &input.value_type); + self.assert_type_is_defined(&input.value_type, 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)), @@ -134,9 +140,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { // Type check the function's parameters. function.input.iter().for_each(|input_var| { - // Check that the type of input parameter is valid. - self.assert_type_is_valid(input_var.span(), &input_var.type_()); - self.assert_not_tuple(input_var.span(), &input_var.type_()); + // Check that the type of input parameter is defined. + self.assert_type_is_defined(&input_var.type_(), input_var.span()); + // Check that type of the input parameter is valid. + self.assert_valid_declaration_or_parameter_type(&input_var.type_(), input_var.span()); match self.is_transition_function { // If the function is a transition function, then check that the parameter mode is not a constant. @@ -168,8 +175,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { match output_type { Output::External(_) => {} // Do not type check external record function outputs. Output::Internal(output_type) => { + // Check that the type of output is defined. + self.assert_type_is_defined(&output_type.type_, output_type.span); // Check that the type of output is valid. - self.assert_type_is_valid(output_type.span, &output_type.type_); + self.assert_valid_declaration_or_parameter_type(&output_type.type_, output_type.span); // Check that the mode of the output is valid. if output_type.mode == Mode::Const { @@ -181,8 +190,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { self.visit_block(&function.block); + // Check that the return type is defined. + self.assert_type_is_defined(&function.output_type, function.span); // Check that the return type is valid. - self.assert_type_is_valid(function.span, &function.output_type); + self.assert_valid_declaration_or_parameter_type(&function.output_type, function.span); // If the function has a return type, then check that it has a return. if function.output_type != Type::Unit && !self.has_return { @@ -225,9 +236,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { let scope_index = self.create_child_scope(); finalize.input.iter().for_each(|input_var| { + // Check that the type of input parameter is defined. + self.assert_type_is_defined(&input_var.type_(), input_var.span()); // Check that the type of input parameter is valid. - self.assert_type_is_valid(input_var.span(), &input_var.type_()); - self.assert_not_tuple(input_var.span(), &input_var.type_()); + self.assert_valid_declaration_or_parameter_type(&input_var.type_(), input_var.span()); // Check that the input parameter is not constant or private. if input_var.mode() == Mode::Const || input_var.mode() == Mode::Private { @@ -249,8 +261,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { // Type check the function's return type. finalize.output.iter().for_each(|output_type| { + // Check that the type of output is defined. + self.assert_type_is_defined(&output_type.type_(), output_type.span()); // Check that the type of output is valid. - self.assert_type_is_valid(output_type.span(), &output_type.type_()); + self.assert_valid_declaration_or_parameter_type(&output_type.type_(), output_type.span()); // Check that the mode of the output is valid. if output_type.mode() == Mode::Const { @@ -267,8 +281,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { // Type check the finalize block. self.visit_block(&finalize.block); + // Check that the return type is defined. + self.assert_type_is_defined(&finalize.output_type, finalize.span); // Check that the return type is valid. - self.assert_type_is_valid(finalize.span, &finalize.output_type); + self.assert_valid_declaration_or_parameter_type(&finalize.output_type, finalize.span); // If the function has a return type, then check that it has a return. if finalize.output_type != Type::Unit && !self.has_return { diff --git a/compiler/passes/src/type_checking/check_statements.rs b/compiler/passes/src/type_checking/check_statements.rs index a1c3782b73..75ab3149f2 100644 --- a/compiler/passes/src/type_checking/check_statements.rs +++ b/compiler/passes/src/type_checking/check_statements.rs @@ -59,12 +59,6 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> { _ => {} } - match &var.type_ { - Type::Unit => self.emit_err(TypeCheckerError::assign_unit_expression_to_variable(input.span)), - Type::Tuple(tuple) if tuple.len() == 1 => self.emit_err(TypeCheckerError::singleton_tuple(input.span)), - _ => (), // Do nothing - } - Some(var.type_.clone()) } else { self.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span)); @@ -192,17 +186,16 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> { VariableType::Mut }; + // Check that the type of the definition is defined. + self.assert_type_is_defined(&input.type_, input.span); + // Check that the type of the definition is valid. - self.assert_type_is_valid(input.span, &input.type_); - - match &input.type_ { - Type::Unit => self.emit_err(TypeCheckerError::assign_unit_expression_to_variable(input.span)), - Type::Tuple(tuple) if tuple.len() == 1 => self.emit_err(TypeCheckerError::singleton_tuple(input.span)), - _ => (), // Do nothing - } + self.assert_valid_declaration_or_parameter_type(&input.type_, input.span); + // Check the expression on the left-hand side. self.visit_expression(&input.value, &Some(input.type_.clone())); + // Insert the variable into the symbol table. if let Err(err) = self.symbol_table.borrow_mut().insert_variable( input.variable_name.name, VariableSymbol { diff --git a/compiler/passes/src/type_checking/checker.rs b/compiler/passes/src/type_checking/checker.rs index 2ebda3353f..aec2f67b4b 100644 --- a/compiler/passes/src/type_checking/checker.rs +++ b/compiler/passes/src/type_checking/checker.rs @@ -387,8 +387,8 @@ impl<'a> TypeChecker<'a> { } } - /// Emits an error if the type is not valid. - pub(crate) fn assert_type_is_valid(&self, span: Span, type_: &Type) { + /// Emits an error if the type or its constituent types are not defined. + pub(crate) fn assert_type_is_defined(&self, type_: &Type, span: Span) { match type_ { // String types are temporarily disabled. Type::String => { @@ -401,13 +401,13 @@ impl<'a> TypeChecker<'a> { // Check that the constituent types of the tuple are valid. Type::Tuple(tuple_type) => { for type_ in tuple_type.iter() { - self.assert_type_is_valid(span, type_) + self.assert_type_is_defined(type_, span) } } // Check that the constituent types of mapping are valid. Type::Mapping(mapping_type) => { - self.assert_type_is_valid(span, &mapping_type.key); - self.assert_type_is_valid(span, &mapping_type.value); + self.assert_type_is_defined(&mapping_type.key, span); + self.assert_type_is_defined(&mapping_type.value, span); } _ => {} // Do nothing. } @@ -422,6 +422,22 @@ impl<'a> TypeChecker<'a> { span, ) } + + // TODO: Fuse with defined check + // TODO: Do we need to check that an identifier does not correspond to a mapping type? + /// Emits an error if the type on the left-hand side of the assignment is invalid. + pub(crate) fn assert_valid_declaration_or_parameter_type(&self, type_: &Type, span: Span) { + match type_ { + // If the type is an empty tuple, return an error. + Type::Unit => self.emit_err(TypeCheckerError::unit_tuple(span)), + // If the type is a singleton tuple, return an error. + Type::Tuple(tuple) if tuple.len() == 1 => self.emit_err(TypeCheckerError::singleton_tuple(span)), + // The type can never be a mapping or error type. + Type::Mapping(_) | Type::Err => unreachable!(), + // Otherwise, the type is valid. + _ => (), // Do nothing + } + } } fn types_to_string(types: &[Type]) -> String { diff --git a/errors/src/errors/type_checker/type_checker_error.rs b/errors/src/errors/type_checker/type_checker_error.rs index dd265eec03..887cf96857 100644 --- a/errors/src/errors/type_checker/type_checker_error.rs +++ b/errors/src/errors/type_checker/type_checker_error.rs @@ -453,19 +453,19 @@ create_messages!( help: None, } - // TODO: Eventually update to warnings. + // TODO: Better error messages for each tuple case. e.g tuple in function parameter, tuple in assignment, tuple in return, etc. + @formatted singleton_tuple { args: (), - msg: format!("Tuples of a single element are not allowed."), + msg: format!("Singleton tuple expressions and tuple types are not allowed."), help: None, } - // TODO: Eventually update to warnings. @formatted unit_tuple { args: (), - msg: format!("Tuples of a zero elements are not allowed."), + msg: format!("Empty tuple expressions and tuple types are not allowed."), help: None, } );