Merge pull request #2014 from AleoHQ/fix/error-on-unrecognized-type

Check for Unrecognized Type
This commit is contained in:
Collin Chin 2022-08-15 15:16:23 -07:00 committed by GitHub
commit 4d18031228
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 94 additions and 5 deletions

View File

@ -149,7 +149,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
} }
} }
} else { } 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_) => { Some(type_) => {

View File

@ -43,6 +43,8 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
self.has_return = false; self.has_return = false;
self.parent = Some(input.name()); self.parent = Some(input.name());
input.input.iter().for_each(|input_var| { 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_); 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. // 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 { if !self.has_return {
self.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span())); 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. // 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) { fn visit_circuit(&mut self, input: &'a Circuit) {
// Check for conflicting circuit/record member names. // Check for conflicting circuit/record member names.
let mut used = HashSet::new(); 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 { self.emit_err(if input.is_record {
TypeCheckerError::duplicate_record_variable(input.name(), input.span()) TypeCheckerError::duplicate_record_variable(input.name(), input.span())
} else { } else {

View File

@ -61,6 +61,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
VariableType::Mut 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())); self.visit_expression(&input.value, &Some(input.type_.clone()));
if let Err(err) = self.symbol_table.borrow_mut().insert_variable( if let Err(err) = self.symbol_table.borrow_mut().insert_variable(

View File

@ -331,6 +331,23 @@ impl<'a> TypeChecker<'a> {
self.emit_err(TypeCheckerError::tuple_not_allowed(span)) 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 { fn types_to_string(types: &[Type]) -> String {

View File

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

View File

@ -0,0 +1,14 @@
/*
namespace: Compile
expectation: Fail
*/
circuit Foo {
a: u8,
bar: Bar,
}
@program
function main(a: u8) -> u8 {
return a + 1u8;
}

View File

@ -0,0 +1,14 @@
/*
namespace: Compile
expectation: Fail
*/
@program
function main(a: u8, foo: Foo) -> u8 {
return a;
}
@program
function returns_foo(a: u8) -> Foo {
return a;
}

View File

@ -0,0 +1,11 @@
/*
namespace: Compile
expectation: Fail
input_file: inputs/dummy.in
*/
@program
function main(k: bool) -> bool {
let b: Foo = 1u8;
return k == true;
}

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372017]: The type `Bar` is not found in the current scope.\n --> compiler-test:3:1\n |\n 3 | circuit Foo {\n 4 | a: u8,\n 5 | bar: Bar,\n 6 | }\n | ^\n"

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372017]: The type `Foo` is not found in the current scope.\n --> compiler-test:4:22\n |\n 4 | function main(a: u8, foo: Foo) -> u8 {\n | ^^^\nError [ETYC0372003]: Expected type `circuit Foo` but type `u8` was found\n --> compiler-test:9:22\n |\n 9 | function returns_foo(a: u8) -> Foo {\n | ^\nError [ETYC0372017]: The type `Foo` is not found in the current scope.\n --> compiler-test:9:1\n |\n 9 | function returns_foo(a: u8) -> Foo {\n 10 | return a;\n 11 | }\n | ^\n"

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372017]: The type `Foo` is not found in the current scope.\n --> compiler-test:5:2\n |\n 5 | \tlet b: Foo = 1u8;\n | ^^^^^^^^^^^^^^^^\nError [ETYC0372003]: Expected type `circuit Foo` but type `u8` was found\n --> compiler-test:5:15\n |\n 5 | \tlet b: Foo = 1u8;\n | ^^^\n"