mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-24 02:31:44 +03:00
Merge pull request #2014 from AleoHQ/fix/error-on-unrecognized-type
Check for Unrecognized Type
This commit is contained in:
commit
4d18031228
@ -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_) => {
|
||||||
|
@ -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 {
|
||||||
|
@ -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(
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
14
tests/compiler/circuits/unknown_member_type_fail.leo
Normal file
14
tests/compiler/circuits/unknown_member_type_fail.leo
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
namespace: Compile
|
||||||
|
expectation: Fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
circuit Foo {
|
||||||
|
a: u8,
|
||||||
|
bar: Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
@program
|
||||||
|
function main(a: u8) -> u8 {
|
||||||
|
return a + 1u8;
|
||||||
|
}
|
14
tests/compiler/function/unknown_parameter_type_fail.leo
Normal file
14
tests/compiler/function/unknown_parameter_type_fail.leo
Normal 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;
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
@ -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"
|
@ -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"
|
@ -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"
|
Loading…
Reference in New Issue
Block a user