Tyc checks that types are defined

This commit is contained in:
Pranav Gaddamadugu 2022-08-11 00:37:04 -07:00
parent a69954b64a
commit 974e93cadf
5 changed files with 42 additions and 5 deletions

View File

@ -146,7 +146,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
}
} else {
self.emit_err(TypeCheckerError::invalid_circuit(&access.inner, access.inner.span()));
self.emit_err(TypeCheckerError::undefined_type(&access.inner, access.inner.span()));
}
}
Some(type_) => {

View File

@ -43,6 +43,8 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
self.has_return = false;
self.parent = Some(input.name());
input.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_);
// If the function is not a program function, then check that the parameters do not have an associated mode.
@ -68,6 +70,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
if !self.has_return {
self.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()));
} else {
// Check that the return type is valid.
// TODO: Span should be just for the return type.
self.assert_type_is_valid(input.span, &input.output);
}
// Ensure there are no nested tuples in the return type.
@ -88,7 +94,16 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
fn visit_circuit(&mut self, input: &'a Circuit) {
// Check for conflicting circuit/record member names.
let mut used = HashSet::new();
if !input.members.iter().all(|member| used.insert(member.name())) {
if !input
.members
.iter()
.all(|CircuitMember::CircuitVariable(ident, type_)| {
// TODO: Better spans.
// Check that the member types are valid.
self.assert_type_is_valid(input.span, type_);
used.insert(ident.name)
})
{
self.emit_err(if input.is_record {
TypeCheckerError::duplicate_record_variable(input.name(), input.span())
} else {

View File

@ -61,6 +61,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
VariableType::Mut
};
// Check that the type of the definition is valid.
self.assert_type_is_valid(input.span, &input.type_);
self.visit_expression(&input.value, &Some(input.type_.clone()));
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(

View File

@ -317,6 +317,25 @@ impl<'a> TypeChecker<'a> {
self.emit_err(TypeCheckerError::tuple_not_allowed(span))
}
}
/// Emits an error if the type is not valid.
pub(crate) fn assert_type_is_valid(&self, span: Span, type_: &Type) {
match type_ {
// Check that the named composite type has been defined.
Type::Identifier(identifier) => {
if self.symbol_table.borrow().lookup_circuit(identifier.name).is_none() {
self.emit_err(TypeCheckerError::undefined_type(identifier.name, span));
}
}
// Check that the constituent types are valid.
Type::Tuple(tuple_type) => {
for type_ in tuple_type.iter() {
self.assert_type_is_valid(span, type_)
}
}
_ => {} // Do nothing.
}
}
}
fn types_to_string(types: &[Type]) -> String {

View File

@ -193,10 +193,10 @@ create_messages!(
/// Attempted to access an invalid circuit.
@formatted
invalid_circuit {
args: (circuit: impl Display),
undefined_type {
args: (type_: impl Display),
msg: format!(
"Circuit {circuit} is not found in the current scope."
"The type `{type_}` is not found in the current scope."
),
help: None,
}