From 136be06af9c1496aac81f19078f0467dfc33f67a Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Thu, 18 Apr 2024 16:28:59 -0400 Subject: [PATCH 01/11] wip adding test for self-referential structs, test case failing with ICE --- .../src/hir/resolution/resolver.rs | 27 +- .../noirc_frontend/src/hir/type_check/mod.rs | 31 + compiler/noirc_frontend/src/node_interner.rs | 4 +- compiler/noirc_frontend/src/tests.rs | 2379 +++++++++-------- .../self_referential_struct/Nargo.toml | 7 + .../self_referential_struct/src/main.nr | 11 + 6 files changed, 1267 insertions(+), 1192 deletions(-) create mode 100644 test_programs/compile_failure/self_referential_struct/Nargo.toml create mode 100644 test_programs/compile_failure/self_referential_struct/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 479f357126a..a047d1d4eb1 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -507,7 +507,13 @@ impl<'a> Resolver<'a> { Unit => Type::Unit, Unspecified => Type::Error, Error => Type::Error, - Named(path, args, _) => self.resolve_named_type(path, args, new_variables), + Named(path, args, _) => { + // TODO: remove before PR + // dbg!("calling resolve_named_type.."); + let result = self.resolve_named_type(path, args, new_variables); + // dbg!("called resolve_named_type: {:?}", result.clone()); + result + }, TraitAsType(path, args) => self.resolve_trait_as_type(path, args, new_variables), Tuple(fields) => { @@ -566,6 +572,11 @@ impl<'a> Resolver<'a> { args: Vec, new_variables: &mut Generics, ) -> Type { + // TODO: remove before PR + // if self.current_item.is_some() { + // panic!("resolve_named_type: self {:?}, path {:?}, args {:?}, new vars {:?}", self.current_item, path.clone(), args.clone(), new_variables.clone()); + // } + if args.is_empty() { if let Some(typ) = self.lookup_generic_or_global_type(&path) { return typ; @@ -617,6 +628,15 @@ impl<'a> Resolver<'a> { return Type::Alias(alias, args); } + // TODO: remove before PR + // dbg!("structs: {:?}", &self.interner.structs); + if let Some(current_item_id) = self.current_item { + dbg!("dependency: {:?}", self.interner.get_or_insert_dependency(current_item_id)); + dbg!("dependency: {:?}", self.interner.check_for_dependency_cycles()); + } + dbg!("lookup_struct_or_error: self {:?}, path {:?}, args {:?}, new vars {:?}", self.current_item, path.clone(), args.clone(), new_variables.clone()); + dbg!("ok: {:?}", self.lookup_struct_or_error(path.clone())); + match self.lookup_struct_or_error(path) { Some(struct_type) => { let expected_generic_count = struct_type.borrow().generics.len(); @@ -883,6 +903,11 @@ impl<'a> Resolver<'a> { unresolved: NoirStruct, struct_id: StructId, ) -> (Generics, Vec<(Ident, Type)>, Vec) { + + dbg!("resolve_struct_fields: {:?}", unresolved.clone().name); + // dbg!("resolve_struct_fields: {:?}, {:?}, {:?}", &self.interner.structs, unresolved.clone(), struct_id); + panic!("resolve_struct_fields: {:?}, {:?}, {:?}", &self.interner.structs, unresolved, struct_id); + let generics = self.add_generics(&unresolved.generics); // Check whether the struct definition has globals in the local module and add them to the scope diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index f5323cd07de..e86226cfdf4 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -614,6 +614,37 @@ pub mod test { type_check_src_code(src, vec![String::from("main")]); } + #[test] + fn self_referential_struct() { + let src = r#" + struct Option { + _is_some: bool, + _value: T, + } + + impl Option { + /// Constructs a None value + pub fn none() -> Self { + Self { _is_some: false, _value: crate::unsafe::zeroed() } + } + } + + struct SelfReferential + { + prop : Option + } + + // #[test] + // unconstrained + // fn test_self_referential() + // { + // let self_ref = SelfReferential { prop : Option::none() }; + // } + "#; + + type_check_src_code(src, vec![String::from("main")]); + } + #[test] fn closure_with_no_args() { let src = r#" diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 5b375be8d56..fd10fb8b2ce 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -88,7 +88,7 @@ pub struct NodeInterner { // Each struct definition is possibly shared across multiple type nodes. // It is also mutated through the RefCell during name resolution to append // methods from impls to the type. - structs: HashMap>, + pub(crate) structs: HashMap>, struct_attributes: HashMap, @@ -1579,7 +1579,7 @@ impl NodeInterner { self.dependency_graph.update_edge(dependent_index, dependency_index, ()); } - fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { + pub(crate) fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { if let Some(index) = self.dependency_graph_indices.get(&id) { return *index; } diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index c4f0a8d67ba..b6a4bf9ebac 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -91,1194 +91,1195 @@ mod test { get_program(src).2 } - #[test] - fn check_trait_implemented_for_all_t() { - let src = " - trait Default { - fn default() -> Self; - } - - trait Eq { - fn eq(self, other: Self) -> bool; - } - - trait IsDefault { - fn is_default(self) -> bool; - } - - impl IsDefault for T where T: Default + Eq { - fn is_default(self) -> bool { - self.eq(T::default()) - } - } - - struct Foo { - a: u64, - } - - impl Eq for Foo { - fn eq(self, other: Foo) -> bool { self.a == other.a } - } - - impl Default for u64 { - fn default() -> Self { - 0 - } - } - - impl Default for Foo { - fn default() -> Self { - Foo { a: Default::default() } - } - } - - fn main(a: Foo) -> pub bool { - a.is_default() - }"; - - let errors = get_program_errors(src); - errors.iter().for_each(|err| println!("{:?}", err)); - assert!(errors.is_empty()); - } - - #[test] - fn check_trait_implementation_duplicate_method() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Field; - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - impl Default for Foo { - // Duplicate trait methods should not compile - fn default(x: Field, y: Field) -> Field { - y + 2 * x - } - // Duplicate trait methods should not compile - fn default(x: Field, y: Field) -> Field { - x + 2 * y - } - } - - fn main() {}"; - - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { - typ, - first_def, - second_def, - }) => { - assert_eq!(typ, &DuplicateType::TraitAssociatedFunction); - assert_eq!(first_def, "default"); - assert_eq!(second_def, "default"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_method_return_type() { - let src = " - trait Default { - fn default() -> Self; - } - - struct Foo { - } - - impl Default for Foo { - fn default() -> Field { - 0 - } - } - - fn main() { - } - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::TypeError(TypeCheckError::TypeMismatch { - expected_typ, - expr_typ, - expr_span: _, - }) => { - assert_eq!(expected_typ, "Foo"); - assert_eq!(expr_typ, "Field"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_method_return_type2() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Self; - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - impl Default for Foo { - fn default(x: Field, _y: Field) -> Field { - x - } - } - - fn main() { - }"; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::TypeError(TypeCheckError::TypeMismatch { - expected_typ, - expr_typ, - expr_span: _, - }) => { - assert_eq!(expected_typ, "Foo"); - assert_eq!(expr_typ, "Field"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_missing_implementation() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Self; - - fn method2(x: Field) -> Field; - - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - impl Default for Foo { - fn default(x: Field, y: Field) -> Self { - Self { bar: x, array: [x,y] } - } - } - - fn main() { - } - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::TraitMissingMethod { - trait_name, - method_name, - trait_impl_span: _, - }) => { - assert_eq!(trait_name, "Default"); - assert_eq!(method_name, "method2"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_not_in_scope() { - let src = " - struct Foo { - bar: Field, - array: [Field; 2], - } - - // Default trait does not exist - impl Default for Foo { - fn default(x: Field, y: Field) -> Self { - Self { bar: x, array: [x,y] } - } - } - - fn main() { - } - - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::TraitNotFound { - trait_path, - }) => { - assert_eq!(trait_path.as_string(), "Default"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_method_name() { - let src = " - trait Default { - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - // wrong trait name method should not compile - impl Default for Foo { - fn does_not_exist(x: Field, y: Field) -> Self { - Self { bar: x, array: [x,y] } - } - } - - fn main() { - }"; - let compilation_errors = get_program_errors(src); - assert!(!has_parser_error(&compilation_errors)); - assert!( - compilation_errors.len() == 1, - "Expected 1 compilation error, got: {:?}", - compilation_errors - ); - - for (err, _file_id) in compilation_errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::MethodNotInTrait { - trait_name, - impl_method, - }) => { - assert_eq!(trait_name, "Default"); - assert_eq!(impl_method, "does_not_exist"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_parameter() { - let src = " - trait Default { - fn default(x: Field) -> Self; - } - - struct Foo { - bar: u32, - } - - impl Default for Foo { - fn default(x: u32) -> Self { - Foo {bar: x} - } - } - - fn main() { - } - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { - method_name, - expected_typ, - actual_typ, - .. - }) => { - assert_eq!(method_name, "default"); - assert_eq!(expected_typ, "Field"); - assert_eq!(actual_typ, "u32"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_parameter2() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Self; - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - impl Default for Foo { - fn default(x: Field, y: Foo) -> Self { - Self { bar: x, array: [x, y.bar] } - } - } - - fn main() { - }"; - - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { - method_name, - expected_typ, - actual_typ, - .. - }) => { - assert_eq!(method_name, "default"); - assert_eq!(expected_typ, "Field"); - assert_eq!(actual_typ, "Foo"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_parameter_type() { - let src = " - trait Default { - fn default(x: Field, y: NotAType) -> Field; - } - - fn main(x: Field, y: Field) { - assert(y == x); - }"; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::ResolverError(ResolverError::PathResolutionError( - PathResolutionError::Unresolved(ident), - )) => { - assert_eq!(ident, "NotAType"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_wrong_parameters_count() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Self; - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - impl Default for Foo { - fn default(x: Field) -> Self { - Self { bar: x, array: [x, x] } - } - } - - fn main() { - } - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::TypeError(TypeCheckError::MismatchTraitImplNumParameters { - actual_num_parameters, - expected_num_parameters, - trait_name, - method_name, - .. - }) => { - assert_eq!(actual_num_parameters, &1_usize); - assert_eq!(expected_num_parameters, &2_usize); - assert_eq!(method_name, "default"); - assert_eq!(trait_name, "Default"); - } - _ => { - panic!("No other errors are expected in this test case! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_impl_for_non_type() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Field; - } - - impl Default for main { - fn default(x: Field, y: Field) -> Field { - x + y - } - } - - fn main() {} - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::ResolverError(ResolverError::Expected { - expected, got, .. - }) => { - assert_eq!(expected, "type"); - assert_eq!(got, "function"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_impl_struct_not_trait() { - let src = " - struct Foo { - bar: Field, - array: [Field; 2], - } - - struct Default { - x: Field, - z: Field, - } - - // Default is struct not a trait - impl Default for Foo { - fn default(x: Field, y: Field) -> Self { - Self { bar: x, array: [x,y] } - } - } - - fn main() { - } - - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::NotATrait { - not_a_trait_name, - }) => { - assert_eq!(not_a_trait_name.to_string(), "plain::Default"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_duplicate_declaration() { - let src = " - trait Default { - fn default(x: Field, y: Field) -> Self; - } - - struct Foo { - bar: Field, - array: [Field; 2], - } - - impl Default for Foo { - fn default(x: Field,y: Field) -> Self { - Self { bar: x, array: [x,y] } - } - } - - - trait Default { - fn default(x: Field) -> Self; - } - - fn main() { - }"; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { - typ, - first_def, - second_def, - }) => { - assert_eq!(typ, &DuplicateType::Trait); - assert_eq!(first_def, "Default"); - assert_eq!(second_def, "Default"); - } - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_duplicate_implementation() { - let src = " - trait Default { - } - struct Foo { - bar: Field, - } - - impl Default for Foo { - } - impl Default for Foo { - } - fn main() { - } - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { - .. - }) => (), - CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { - .. - }) => (), - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - #[test] - fn check_trait_duplicate_implementation_with_alias() { - let src = " - trait Default { - } - - struct MyStruct { - } - - type MyType = MyStruct; - - impl Default for MyStruct { - } - - impl Default for MyType { - } - - fn main() { - } - "; - let errors = get_program_errors(src); - assert!(!has_parser_error(&errors)); - assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); - for (err, _file_id) in errors { - match &err { - CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { - .. - }) => (), - CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { - .. - }) => (), - _ => { - panic!("No other errors are expected! Found = {:?}", err); - } - }; - } - } - - fn get_program_captures(src: &str) -> Vec> { - let (program, context, _errors) = get_program(src); - let interner = context.def_interner; - let mut all_captures: Vec> = Vec::new(); - for func in program.into_sorted().functions { - let func_id = interner.find_function(func.name()).unwrap(); - let hir_func = interner.function(&func_id); - // Iterate over function statements and apply filtering function - find_lambda_captures( - hir_func.block(&interner).statements(), - &interner, - &mut all_captures, - ); - } - all_captures - } - - fn find_lambda_captures( - stmts: &[StmtId], - interner: &NodeInterner, - result: &mut Vec>, - ) { - for stmt_id in stmts.iter() { - let hir_stmt = interner.statement(stmt_id); - let expr_id = match hir_stmt { - HirStatement::Expression(expr_id) => expr_id, - HirStatement::Let(let_stmt) => let_stmt.expression, - HirStatement::Assign(assign_stmt) => assign_stmt.expression, - HirStatement::Constrain(constr_stmt) => constr_stmt.0, - HirStatement::Semi(semi_expr) => semi_expr, - HirStatement::For(for_loop) => for_loop.block, - HirStatement::Error => panic!("Invalid HirStatement!"), - HirStatement::Break => panic!("Unexpected break"), - HirStatement::Continue => panic!("Unexpected continue"), - }; - let expr = interner.expression(&expr_id); - - get_lambda_captures(expr, interner, result); // TODO: dyn filter function as parameter - } - } - - fn get_lambda_captures( - expr: HirExpression, - interner: &NodeInterner, - result: &mut Vec>, - ) { - if let HirExpression::Lambda(lambda_expr) = expr { - let mut cur_capture = Vec::new(); - - for capture in lambda_expr.captures.iter() { - cur_capture.push(interner.definition(capture.ident.id).name.clone()); - } - result.push(cur_capture); - - // Check for other captures recursively within the lambda body - let hir_body_expr = interner.expression(&lambda_expr.body); - if let HirExpression::Block(block_expr) = hir_body_expr { - find_lambda_captures(block_expr.statements(), interner, result); - } - } - } - - #[test] - fn resolve_empty_function() { - let src = " - fn main() { - - } - "; - assert!(get_program_errors(src).is_empty()); - } - #[test] - fn resolve_basic_function() { - let src = r#" - fn main(x : Field) { - let y = x + x; - assert(y == x); - } - "#; - assert!(get_program_errors(src).is_empty()); - } - #[test] - fn resolve_unused_var() { - let src = r#" - fn main(x : Field) { - let y = x + x; - assert(x == x); - } - "#; - - let errors = get_program_errors(src); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - // It should be regarding the unused variable - match &errors[0].0 { - CompilationError::ResolverError(ResolverError::UnusedVariable { ident }) => { - assert_eq!(&ident.0.contents, "y"); - } - _ => unreachable!("we should only have an unused var error"), - } - } - - #[test] - fn resolve_unresolved_var() { - let src = r#" - fn main(x : Field) { - let y = x + x; - assert(y == z); - } - "#; - let errors = get_program_errors(src); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - // It should be regarding the unresolved var `z` (Maybe change to undeclared and special case) - match &errors[0].0 { - CompilationError::ResolverError(ResolverError::VariableNotDeclared { - name, - span: _, - }) => assert_eq!(name, "z"), - _ => unimplemented!("we should only have an unresolved variable"), - } - } - - #[test] - fn unresolved_path() { - let src = " - fn main(x : Field) { - let _z = some::path::to::a::func(x); - } - "; - let errors = get_program_errors(src); - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - for (compilation_error, _file_id) in errors { - match compilation_error { - CompilationError::ResolverError(err) => { - match err { - ResolverError::PathResolutionError(PathResolutionError::Unresolved( - name, - )) => { - assert_eq!(name.to_string(), "some"); - } - _ => unimplemented!("we should only have an unresolved function"), - }; - } - _ => unimplemented!(), - } - } - } - - #[test] - fn resolve_literal_expr() { - let src = r#" - fn main(x : Field) { - let y = 5; - assert(y == x); - } - "#; - assert!(get_program_errors(src).is_empty()); - } - - #[test] - fn multiple_resolution_errors() { - let src = r#" - fn main(x : Field) { - let y = foo::bar(x); - let z = y + a; - } - "#; - - let errors = get_program_errors(src); - assert!(errors.len() == 3, "Expected 3 errors, got: {:?}", errors); - - // Errors are: - // `a` is undeclared - // `z` is unused - // `foo::bar` does not exist - for (compilation_error, _file_id) in errors { - match compilation_error { - CompilationError::ResolverError(err) => { - match err { - ResolverError::UnusedVariable { ident } => { - assert_eq!(&ident.0.contents, "z"); - } - ResolverError::VariableNotDeclared { name, .. } => { - assert_eq!(name, "a"); - } - ResolverError::PathResolutionError(PathResolutionError::Unresolved( - name, - )) => { - assert_eq!(name.to_string(), "foo"); - } - _ => unimplemented!(), - }; - } - _ => unimplemented!(), - } - } - } - - #[test] - fn resolve_prefix_expr() { - let src = r#" - fn main(x : Field) { - let _y = -x; - } - "#; - assert!(get_program_errors(src).is_empty()); - } - - #[test] - fn resolve_for_expr() { - let src = r#" - fn main(x : u64) { - for i in 1..20 { - let _z = x + i; - }; - } - "#; - assert!(get_program_errors(src).is_empty()); - } - - #[test] - fn resolve_call_expr() { - let src = r#" - fn main(x : Field) { - let _z = foo(x); - } - - fn foo(x : Field) -> Field { - x - } - "#; - assert!(get_program_errors(src).is_empty()); - } - - #[test] - fn resolve_shadowing() { - let src = r#" - fn main(x : Field) { - let x = foo(x); - let x = x; - let (x, x) = (x, x); - let _ = x; - } - - fn foo(x : Field) -> Field { - x - } - "#; - assert!(get_program_errors(src).is_empty()); - } - - #[test] - fn resolve_basic_closure() { - let src = r#" - fn main(x : Field) -> pub Field { - let closure = |y| y + x; - closure(x) - } - "#; - assert!(get_program_errors(src).is_empty()); - } - - #[test] - fn resolve_simplified_closure() { - // based on bug https://github.com/noir-lang/noir/issues/1088 - - let src = r#"fn do_closure(x: Field) -> Field { - let y = x; - let ret_capture = || { - y - }; - ret_capture() - } - - fn main(x: Field) { - assert(do_closure(x) == 100); - } - - "#; - let parsed_captures = get_program_captures(src); - let expected_captures = vec![vec!["y".to_string()]]; - assert_eq!(expected_captures, parsed_captures); - } - - #[test] - fn resolve_complex_closures() { - let src = r#" - fn main(x: Field) -> pub Field { - let closure_without_captures = |x: Field| -> Field { x + x }; - let a = closure_without_captures(1); - - let closure_capturing_a_param = |y: Field| -> Field { y + x }; - let b = closure_capturing_a_param(2); - - let closure_capturing_a_local_var = |y: Field| -> Field { y + b }; - let c = closure_capturing_a_local_var(3); - - let closure_with_transitive_captures = |y: Field| -> Field { - let d = 5; - let nested_closure = |z: Field| -> Field { - let doubly_nested_closure = |w: Field| -> Field { w + x + b }; - a + z + y + d + x + doubly_nested_closure(4) + x + y - }; - let res = nested_closure(5); - res - }; - - a + b + c + closure_with_transitive_captures(6) - } - "#; - assert!(get_program_errors(src).is_empty(), "there should be no errors"); - - let expected_captures = vec![ - vec![], - vec!["x".to_string()], - vec!["b".to_string()], - vec!["x".to_string(), "b".to_string(), "a".to_string()], - vec![ - "x".to_string(), - "b".to_string(), - "a".to_string(), - "y".to_string(), - "d".to_string(), - ], - vec!["x".to_string(), "b".to_string()], - ]; - - let parsed_captures = get_program_captures(src); - - assert_eq!(expected_captures, parsed_captures); - } - - #[test] - fn resolve_fmt_strings() { - let src = r#" - fn main() { - let string = f"this is i: {i}"; - println(string); - - println(f"I want to print {0}"); - - let new_val = 10; - println(f"random_string{new_val}{new_val}"); - } - fn println(x : T) -> T { - x - } - "#; - - let errors = get_program_errors(src); - assert!(errors.len() == 5, "Expected 5 errors, got: {:?}", errors); - - for (err, _file_id) in errors { - match &err { - CompilationError::ResolverError(ResolverError::VariableNotDeclared { - name, - .. - }) => { - assert_eq!(name, "i"); - } - CompilationError::ResolverError(ResolverError::NumericConstantInFormatString { - name, - .. - }) => { - assert_eq!(name, "0"); - } - CompilationError::TypeError(TypeCheckError::UnusedResultError { - expr_type: _, - expr_span, - }) => { - let a = src.get(expr_span.start() as usize..expr_span.end() as usize).unwrap(); - assert!( - a == "println(string)" - || a == "println(f\"I want to print {0}\")" - || a == "println(f\"random_string{new_val}{new_val}\")" - ); - } - _ => unimplemented!(), - }; - } - } - - fn check_rewrite(src: &str, expected: &str) { - let (_program, mut context, _errors) = get_program(src); - let main_func_id = context.def_interner.find_function("main").unwrap(); - let program = monomorphize(main_func_id, &mut context.def_interner).unwrap(); - assert!(format!("{}", program) == expected); - } +// #[test] +// fn check_trait_implemented_for_all_t() { +// let src = " +// trait Default { +// fn default() -> Self; +// } +// +// trait Eq { +// fn eq(self, other: Self) -> bool; +// } +// +// trait IsDefault { +// fn is_default(self) -> bool; +// } +// +// impl IsDefault for T where T: Default + Eq { +// fn is_default(self) -> bool { +// self.eq(T::default()) +// } +// } +// +// struct Foo { +// a: u64, +// } +// +// impl Eq for Foo { +// fn eq(self, other: Foo) -> bool { self.a == other.a } +// } +// +// impl Default for u64 { +// fn default() -> Self { +// 0 +// } +// } +// +// impl Default for Foo { +// fn default() -> Self { +// Foo { a: Default::default() } +// } +// } +// +// fn main(a: Foo) -> pub bool { +// a.is_default() +// }"; +// +// let errors = get_program_errors(src); +// errors.iter().for_each(|err| println!("{:?}", err)); +// assert!(errors.is_empty()); +// } +// +// #[test] +// fn check_trait_implementation_duplicate_method() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Field; +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// impl Default for Foo { +// // Duplicate trait methods should not compile +// fn default(x: Field, y: Field) -> Field { +// y + 2 * x +// } +// // Duplicate trait methods should not compile +// fn default(x: Field, y: Field) -> Field { +// x + 2 * y +// } +// } +// +// fn main() {}"; +// +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { +// typ, +// first_def, +// second_def, +// }) => { +// assert_eq!(typ, &DuplicateType::TraitAssociatedFunction); +// assert_eq!(first_def, "default"); +// assert_eq!(second_def, "default"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_method_return_type() { +// let src = " +// trait Default { +// fn default() -> Self; +// } +// +// struct Foo { +// } +// +// impl Default for Foo { +// fn default() -> Field { +// 0 +// } +// } +// +// fn main() { +// } +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::TypeError(TypeCheckError::TypeMismatch { +// expected_typ, +// expr_typ, +// expr_span: _, +// }) => { +// assert_eq!(expected_typ, "Foo"); +// assert_eq!(expr_typ, "Field"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_method_return_type2() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Self; +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// impl Default for Foo { +// fn default(x: Field, _y: Field) -> Field { +// x +// } +// } +// +// fn main() { +// }"; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::TypeError(TypeCheckError::TypeMismatch { +// expected_typ, +// expr_typ, +// expr_span: _, +// }) => { +// assert_eq!(expected_typ, "Foo"); +// assert_eq!(expr_typ, "Field"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_missing_implementation() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Self; +// +// fn method2(x: Field) -> Field; +// +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// impl Default for Foo { +// fn default(x: Field, y: Field) -> Self { +// Self { bar: x, array: [x,y] } +// } +// } +// +// fn main() { +// } +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::TraitMissingMethod { +// trait_name, +// method_name, +// trait_impl_span: _, +// }) => { +// assert_eq!(trait_name, "Default"); +// assert_eq!(method_name, "method2"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_not_in_scope() { +// let src = " +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// // Default trait does not exist +// impl Default for Foo { +// fn default(x: Field, y: Field) -> Self { +// Self { bar: x, array: [x,y] } +// } +// } +// +// fn main() { +// } +// +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::TraitNotFound { +// trait_path, +// }) => { +// assert_eq!(trait_path.as_string(), "Default"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_method_name() { +// let src = " +// trait Default { +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// // wrong trait name method should not compile +// impl Default for Foo { +// fn does_not_exist(x: Field, y: Field) -> Self { +// Self { bar: x, array: [x,y] } +// } +// } +// +// fn main() { +// }"; +// let compilation_errors = get_program_errors(src); +// assert!(!has_parser_error(&compilation_errors)); +// assert!( +// compilation_errors.len() == 1, +// "Expected 1 compilation error, got: {:?}", +// compilation_errors +// ); +// +// for (err, _file_id) in compilation_errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::MethodNotInTrait { +// trait_name, +// impl_method, +// }) => { +// assert_eq!(trait_name, "Default"); +// assert_eq!(impl_method, "does_not_exist"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_parameter() { +// let src = " +// trait Default { +// fn default(x: Field) -> Self; +// } +// +// struct Foo { +// bar: u32, +// } +// +// impl Default for Foo { +// fn default(x: u32) -> Self { +// Foo {bar: x} +// } +// } +// +// fn main() { +// } +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { +// method_name, +// expected_typ, +// actual_typ, +// .. +// }) => { +// assert_eq!(method_name, "default"); +// assert_eq!(expected_typ, "Field"); +// assert_eq!(actual_typ, "u32"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_parameter2() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Self; +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// impl Default for Foo { +// fn default(x: Field, y: Foo) -> Self { +// Self { bar: x, array: [x, y.bar] } +// } +// } +// +// fn main() { +// }"; +// +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { +// method_name, +// expected_typ, +// actual_typ, +// .. +// }) => { +// assert_eq!(method_name, "default"); +// assert_eq!(expected_typ, "Field"); +// assert_eq!(actual_typ, "Foo"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_parameter_type() { +// let src = " +// trait Default { +// fn default(x: Field, y: NotAType) -> Field; +// } +// +// fn main(x: Field, y: Field) { +// assert(y == x); +// }"; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::ResolverError(ResolverError::PathResolutionError( +// PathResolutionError::Unresolved(ident), +// )) => { +// assert_eq!(ident, "NotAType"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_wrong_parameters_count() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Self; +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// impl Default for Foo { +// fn default(x: Field) -> Self { +// Self { bar: x, array: [x, x] } +// } +// } +// +// fn main() { +// } +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::TypeError(TypeCheckError::MismatchTraitImplNumParameters { +// actual_num_parameters, +// expected_num_parameters, +// trait_name, +// method_name, +// .. +// }) => { +// assert_eq!(actual_num_parameters, &1_usize); +// assert_eq!(expected_num_parameters, &2_usize); +// assert_eq!(method_name, "default"); +// assert_eq!(trait_name, "Default"); +// } +// _ => { +// panic!("No other errors are expected in this test case! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_impl_for_non_type() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Field; +// } +// +// impl Default for main { +// fn default(x: Field, y: Field) -> Field { +// x + y +// } +// } +// +// fn main() {} +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::ResolverError(ResolverError::Expected { +// expected, got, .. +// }) => { +// assert_eq!(expected, "type"); +// assert_eq!(got, "function"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_impl_struct_not_trait() { +// let src = " +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// struct Default { +// x: Field, +// z: Field, +// } +// +// // Default is struct not a trait +// impl Default for Foo { +// fn default(x: Field, y: Field) -> Self { +// Self { bar: x, array: [x,y] } +// } +// } +// +// fn main() { +// } +// +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::NotATrait { +// not_a_trait_name, +// }) => { +// assert_eq!(not_a_trait_name.to_string(), "plain::Default"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_duplicate_declaration() { +// let src = " +// trait Default { +// fn default(x: Field, y: Field) -> Self; +// } +// +// struct Foo { +// bar: Field, +// array: [Field; 2], +// } +// +// impl Default for Foo { +// fn default(x: Field,y: Field) -> Self { +// Self { bar: x, array: [x,y] } +// } +// } +// +// +// trait Default { +// fn default(x: Field) -> Self; +// } +// +// fn main() { +// }"; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { +// typ, +// first_def, +// second_def, +// }) => { +// assert_eq!(typ, &DuplicateType::Trait); +// assert_eq!(first_def, "Default"); +// assert_eq!(second_def, "Default"); +// } +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_duplicate_implementation() { +// let src = " +// trait Default { +// } +// struct Foo { +// bar: Field, +// } +// +// impl Default for Foo { +// } +// impl Default for Foo { +// } +// fn main() { +// } +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { +// .. +// }) => (), +// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { +// .. +// }) => (), +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// #[test] +// fn check_trait_duplicate_implementation_with_alias() { +// let src = " +// trait Default { +// } +// +// struct MyStruct { +// } +// +// type MyType = MyStruct; +// +// impl Default for MyStruct { +// } +// +// impl Default for MyType { +// } +// +// fn main() { +// } +// "; +// let errors = get_program_errors(src); +// assert!(!has_parser_error(&errors)); +// assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); +// for (err, _file_id) in errors { +// match &err { +// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { +// .. +// }) => (), +// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { +// .. +// }) => (), +// _ => { +// panic!("No other errors are expected! Found = {:?}", err); +// } +// }; +// } +// } +// +// fn get_program_captures(src: &str) -> Vec> { +// let (program, context, _errors) = get_program(src); +// let interner = context.def_interner; +// let mut all_captures: Vec> = Vec::new(); +// for func in program.into_sorted().functions { +// let func_id = interner.find_function(func.name()).unwrap(); +// let hir_func = interner.function(&func_id); +// // Iterate over function statements and apply filtering function +// find_lambda_captures( +// hir_func.block(&interner).statements(), +// &interner, +// &mut all_captures, +// ); +// } +// all_captures +// } +// +// fn find_lambda_captures( +// stmts: &[StmtId], +// interner: &NodeInterner, +// result: &mut Vec>, +// ) { +// for stmt_id in stmts.iter() { +// let hir_stmt = interner.statement(stmt_id); +// let expr_id = match hir_stmt { +// HirStatement::Expression(expr_id) => expr_id, +// HirStatement::Let(let_stmt) => let_stmt.expression, +// HirStatement::Assign(assign_stmt) => assign_stmt.expression, +// HirStatement::Constrain(constr_stmt) => constr_stmt.0, +// HirStatement::Semi(semi_expr) => semi_expr, +// HirStatement::For(for_loop) => for_loop.block, +// HirStatement::Error => panic!("Invalid HirStatement!"), +// HirStatement::Break => panic!("Unexpected break"), +// HirStatement::Continue => panic!("Unexpected continue"), +// }; +// let expr = interner.expression(&expr_id); +// +// get_lambda_captures(expr, interner, result); // TODO: dyn filter function as parameter +// } +// } +// +// fn get_lambda_captures( +// expr: HirExpression, +// interner: &NodeInterner, +// result: &mut Vec>, +// ) { +// if let HirExpression::Lambda(lambda_expr) = expr { +// let mut cur_capture = Vec::new(); +// +// for capture in lambda_expr.captures.iter() { +// cur_capture.push(interner.definition(capture.ident.id).name.clone()); +// } +// result.push(cur_capture); +// +// // Check for other captures recursively within the lambda body +// let hir_body_expr = interner.expression(&lambda_expr.body); +// if let HirExpression::Block(block_expr) = hir_body_expr { +// find_lambda_captures(block_expr.statements(), interner, result); +// } +// } +// } +// +// #[test] +// fn resolve_empty_function() { +// let src = " +// fn main() { +// +// } +// "; +// assert!(get_program_errors(src).is_empty()); +// } +// #[test] +// fn resolve_basic_function() { +// let src = r#" +// fn main(x : Field) { +// let y = x + x; +// assert(y == x); +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// #[test] +// fn resolve_unused_var() { +// let src = r#" +// fn main(x : Field) { +// let y = x + x; +// assert(x == x); +// } +// "#; +// +// let errors = get_program_errors(src); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// // It should be regarding the unused variable +// match &errors[0].0 { +// CompilationError::ResolverError(ResolverError::UnusedVariable { ident }) => { +// assert_eq!(&ident.0.contents, "y"); +// } +// _ => unreachable!("we should only have an unused var error"), +// } +// } +// +// #[test] +// fn resolve_unresolved_var() { +// let src = r#" +// fn main(x : Field) { +// let y = x + x; +// assert(y == z); +// } +// "#; +// let errors = get_program_errors(src); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// // It should be regarding the unresolved var `z` (Maybe change to undeclared and special case) +// match &errors[0].0 { +// CompilationError::ResolverError(ResolverError::VariableNotDeclared { +// name, +// span: _, +// }) => assert_eq!(name, "z"), +// _ => unimplemented!("we should only have an unresolved variable"), +// } +// } +// +// #[test] +// fn unresolved_path() { +// let src = " +// fn main(x : Field) { +// let _z = some::path::to::a::func(x); +// } +// "; +// let errors = get_program_errors(src); +// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); +// for (compilation_error, _file_id) in errors { +// match compilation_error { +// CompilationError::ResolverError(err) => { +// match err { +// ResolverError::PathResolutionError(PathResolutionError::Unresolved( +// name, +// )) => { +// assert_eq!(name.to_string(), "some"); +// } +// _ => unimplemented!("we should only have an unresolved function"), +// }; +// } +// _ => unimplemented!(), +// } +// } +// } +// +// #[test] +// fn resolve_literal_expr() { +// let src = r#" +// fn main(x : Field) { +// let y = 5; +// assert(y == x); +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// +// #[test] +// fn multiple_resolution_errors() { +// let src = r#" +// fn main(x : Field) { +// let y = foo::bar(x); +// let z = y + a; +// } +// "#; +// +// let errors = get_program_errors(src); +// assert!(errors.len() == 3, "Expected 3 errors, got: {:?}", errors); +// +// // Errors are: +// // `a` is undeclared +// // `z` is unused +// // `foo::bar` does not exist +// for (compilation_error, _file_id) in errors { +// match compilation_error { +// CompilationError::ResolverError(err) => { +// match err { +// ResolverError::UnusedVariable { ident } => { +// assert_eq!(&ident.0.contents, "z"); +// } +// ResolverError::VariableNotDeclared { name, .. } => { +// assert_eq!(name, "a"); +// } +// ResolverError::PathResolutionError(PathResolutionError::Unresolved( +// name, +// )) => { +// assert_eq!(name.to_string(), "foo"); +// } +// _ => unimplemented!(), +// }; +// } +// _ => unimplemented!(), +// } +// } +// } +// +// #[test] +// fn resolve_prefix_expr() { +// let src = r#" +// fn main(x : Field) { +// let _y = -x; +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// +// #[test] +// fn resolve_for_expr() { +// let src = r#" +// fn main(x : u64) { +// for i in 1..20 { +// let _z = x + i; +// }; +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// +// #[test] +// fn resolve_call_expr() { +// let src = r#" +// fn main(x : Field) { +// let _z = foo(x); +// } +// +// fn foo(x : Field) -> Field { +// x +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// +// #[test] +// fn resolve_shadowing() { +// let src = r#" +// fn main(x : Field) { +// let x = foo(x); +// let x = x; +// let (x, x) = (x, x); +// let _ = x; +// } +// +// fn foo(x : Field) -> Field { +// x +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// +// #[test] +// fn resolve_basic_closure() { +// let src = r#" +// fn main(x : Field) -> pub Field { +// let closure = |y| y + x; +// closure(x) +// } +// "#; +// assert!(get_program_errors(src).is_empty()); +// } +// +// #[test] +// fn resolve_simplified_closure() { +// // based on bug https://github.com/noir-lang/noir/issues/1088 +// +// let src = r#"fn do_closure(x: Field) -> Field { +// let y = x; +// let ret_capture = || { +// y +// }; +// ret_capture() +// } +// +// fn main(x: Field) { +// assert(do_closure(x) == 100); +// } +// +// "#; +// let parsed_captures = get_program_captures(src); +// let expected_captures = vec![vec!["y".to_string()]]; +// assert_eq!(expected_captures, parsed_captures); +// } +// +// #[test] +// fn resolve_complex_closures() { +// let src = r#" +// fn main(x: Field) -> pub Field { +// let closure_without_captures = |x: Field| -> Field { x + x }; +// let a = closure_without_captures(1); +// +// let closure_capturing_a_param = |y: Field| -> Field { y + x }; +// let b = closure_capturing_a_param(2); +// +// let closure_capturing_a_local_var = |y: Field| -> Field { y + b }; +// let c = closure_capturing_a_local_var(3); +// +// let closure_with_transitive_captures = |y: Field| -> Field { +// let d = 5; +// let nested_closure = |z: Field| -> Field { +// let doubly_nested_closure = |w: Field| -> Field { w + x + b }; +// a + z + y + d + x + doubly_nested_closure(4) + x + y +// }; +// let res = nested_closure(5); +// res +// }; +// +// a + b + c + closure_with_transitive_captures(6) +// } +// "#; +// assert!(get_program_errors(src).is_empty(), "there should be no errors"); +// +// let expected_captures = vec![ +// vec![], +// vec!["x".to_string()], +// vec!["b".to_string()], +// vec!["x".to_string(), "b".to_string(), "a".to_string()], +// vec![ +// "x".to_string(), +// "b".to_string(), +// "a".to_string(), +// "y".to_string(), +// "d".to_string(), +// ], +// vec!["x".to_string(), "b".to_string()], +// ]; +// +// let parsed_captures = get_program_captures(src); +// +// assert_eq!(expected_captures, parsed_captures); +// } +// +// #[test] +// fn resolve_fmt_strings() { +// let src = r#" +// fn main() { +// let string = f"this is i: {i}"; +// println(string); +// +// println(f"I want to print {0}"); +// +// let new_val = 10; +// println(f"random_string{new_val}{new_val}"); +// } +// fn println(x : T) -> T { +// x +// } +// "#; +// +// let errors = get_program_errors(src); +// assert!(errors.len() == 5, "Expected 5 errors, got: {:?}", errors); +// +// for (err, _file_id) in errors { +// match &err { +// CompilationError::ResolverError(ResolverError::VariableNotDeclared { +// name, +// .. +// }) => { +// assert_eq!(name, "i"); +// } +// CompilationError::ResolverError(ResolverError::NumericConstantInFormatString { +// name, +// .. +// }) => { +// assert_eq!(name, "0"); +// } +// CompilationError::TypeError(TypeCheckError::UnusedResultError { +// expr_type: _, +// expr_span, +// }) => { +// let a = src.get(expr_span.start() as usize..expr_span.end() as usize).unwrap(); +// assert!( +// a == "println(string)" +// || a == "println(f\"I want to print {0}\")" +// || a == "println(f\"random_string{new_val}{new_val}\")" +// ); +// } +// _ => unimplemented!(), +// }; +// } +// } +// +// fn check_rewrite(src: &str, expected: &str) { +// let (_program, mut context, _errors) = get_program(src); +// let main_func_id = context.def_interner.find_function("main").unwrap(); +// let program = monomorphize(main_func_id, &mut context.def_interner).unwrap(); +// assert!(format!("{}", program) == expected); +// } +// +// #[test] +// fn simple_closure_with_no_captured_variables() { +// let src = r#" +// fn main() -> pub Field { +// let x = 1; +// let closure = || x; +// closure() +// } +// "#; +// +// let expected_rewrite = r#"fn main$f0() -> Field { +// let x$0 = 1; +// let closure$3 = { +// let closure_variable$2 = { +// let env$1 = (x$l0); +// (env$l1, lambda$f1) +// }; +// closure_variable$l2 +// }; +// { +// let tmp$4 = closure$l3; +// tmp$l4.1(tmp$l4.0) +// } +// } +// fn lambda$f1(mut env$l1: (Field)) -> Field { +// env$l1.0 +// } +// "#; +// check_rewrite(src, expected_rewrite); +// } +// +// #[test] +// fn deny_mutually_recursive_structs() { +// let src = r#" +// struct Foo { bar: Bar } +// struct Bar { foo: Foo } +// fn main() {} +// "#; +// assert_eq!(get_program_errors(src).len(), 1); +// } +// +// #[test] +// fn deny_cyclic_globals() { +// let src = r#" +// global A = B; +// global B = A; +// fn main() {} +// "#; +// assert_eq!(get_program_errors(src).len(), 1); +// } +// +// #[test] +// fn deny_cyclic_type_aliases() { +// let src = r#" +// type A = B; +// type B = A; +// fn main() {} +// "#; +// assert_eq!(get_program_errors(src).len(), 1); +// } +// +// #[test] +// fn ensure_nested_type_aliases_type_check() { +// let src = r#" +// type A = B; +// type B = u8; +// fn main() { +// let _a: A = 0 as u16; +// } +// "#; +// assert_eq!(get_program_errors(src).len(), 1); +// } +// +// #[test] +// fn type_aliases_in_entry_point() { +// let src = r#" +// type Foo = u8; +// fn main(_x: Foo) {} +// "#; +// assert_eq!(get_program_errors(src).len(), 0); +// } +// +// #[test] +// fn operators_in_global_used_in_type() { +// let src = r#" +// global ONE = 1; +// global COUNT = ONE + 2; +// fn main() { +// let _array: [Field; COUNT] = [1, 2, 3]; +// } +// "#; +// assert_eq!(get_program_errors(src).len(), 0); +// } +// +// #[test] +// fn break_and_continue_in_constrained_fn() { +// let src = r#" +// fn main() { +// for i in 0 .. 10 { +// if i == 2 { +// continue; +// } +// if i == 5 { +// break; +// } +// } +// } +// "#; +// assert_eq!(get_program_errors(src).len(), 2); +// } +// +// #[test] +// fn break_and_continue_outside_loop() { +// let src = r#" +// unconstrained fn main() { +// continue; +// break; +// } +// "#; +// assert_eq!(get_program_errors(src).len(), 2); +// } +// +// // Regression for #2540 +// #[test] +// fn for_loop_over_array() { +// let src = r#" +// fn hello(_array: [u1; N]) { +// for _ in 0..N {} +// } +// +// fn main() { +// let array: [u1; 2] = [0, 1]; +// hello(array); +// } +// "#; +// assert_eq!(get_program_errors(src).len(), 0); +// } +// +// // Regression for #4545 +// #[test] +// fn type_aliases_in_main() { +// let src = r#" +// type Outer = [u8; N]; +// fn main(_arg: Outer<1>) {} +// "#; +// assert_eq!(get_program_errors(src).len(), 0); +// } - #[test] - fn simple_closure_with_no_captured_variables() { - let src = r#" - fn main() -> pub Field { - let x = 1; - let closure = || x; - closure() - } - "#; - - let expected_rewrite = r#"fn main$f0() -> Field { - let x$0 = 1; - let closure$3 = { - let closure_variable$2 = { - let env$1 = (x$l0); - (env$l1, lambda$f1) - }; - closure_variable$l2 - }; - { - let tmp$4 = closure$l3; - tmp$l4.1(tmp$l4.0) - } -} -fn lambda$f1(mut env$l1: (Field)) -> Field { - env$l1.0 -} -"#; - check_rewrite(src, expected_rewrite); - } - - #[test] - fn deny_cyclic_structs() { - let src = r#" - struct Foo { bar: Bar } - struct Bar { foo: Foo } - fn main() {} - "#; - assert_eq!(get_program_errors(src).len(), 1); - } - - #[test] - fn deny_cyclic_globals() { - let src = r#" - global A = B; - global B = A; - fn main() {} - "#; - assert_eq!(get_program_errors(src).len(), 1); - } - - #[test] - fn deny_cyclic_type_aliases() { - let src = r#" - type A = B; - type B = A; - fn main() {} - "#; - assert_eq!(get_program_errors(src).len(), 1); - } - - #[test] - fn ensure_nested_type_aliases_type_check() { - let src = r#" - type A = B; - type B = u8; - fn main() { - let _a: A = 0 as u16; - } - "#; - assert_eq!(get_program_errors(src).len(), 1); - } - - #[test] - fn type_aliases_in_entry_point() { - let src = r#" - type Foo = u8; - fn main(_x: Foo) {} - "#; - assert_eq!(get_program_errors(src).len(), 0); - } - - #[test] - fn operators_in_global_used_in_type() { - let src = r#" - global ONE = 1; - global COUNT = ONE + 2; - fn main() { - let _array: [Field; COUNT] = [1, 2, 3]; - } - "#; - assert_eq!(get_program_errors(src).len(), 0); - } - - #[test] - fn break_and_continue_in_constrained_fn() { - let src = r#" - fn main() { - for i in 0 .. 10 { - if i == 2 { - continue; - } - if i == 5 { - break; - } - } - } - "#; - assert_eq!(get_program_errors(src).len(), 2); - } - - #[test] - fn break_and_continue_outside_loop() { - let src = r#" - unconstrained fn main() { - continue; - break; - } - "#; - assert_eq!(get_program_errors(src).len(), 2); - } - - // Regression for #2540 - #[test] - fn for_loop_over_array() { - let src = r#" - fn hello(_array: [u1; N]) { - for _ in 0..N {} - } - - fn main() { - let array: [u1; 2] = [0, 1]; - hello(array); - } - "#; - assert_eq!(get_program_errors(src).len(), 0); - } - - // Regression for #4545 - #[test] - fn type_aliases_in_main() { - let src = r#" - type Outer = [u8; N]; - fn main(_arg: Outer<1>) {} - "#; - assert_eq!(get_program_errors(src).len(), 0); - } } diff --git a/test_programs/compile_failure/self_referential_struct/Nargo.toml b/test_programs/compile_failure/self_referential_struct/Nargo.toml new file mode 100644 index 00000000000..a0693f9d4b1 --- /dev/null +++ b/test_programs/compile_failure/self_referential_struct/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "self_referential_struct" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/self_referential_struct/src/main.nr b/test_programs/compile_failure/self_referential_struct/src/main.nr new file mode 100644 index 00000000000..4c9b0095c71 --- /dev/null +++ b/test_programs/compile_failure/self_referential_struct/src/main.nr @@ -0,0 +1,11 @@ +struct SelfReferential +{ + prop : Option +} + +#[test] +unconstrained +fn test_self_referential() +{ + let self_ref = SelfReferential { prop : Option::none() }; +} From b85f58179ee2a687eeca7e5f3ee30af53374e9d8 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Mon, 22 Apr 2024 15:16:43 -0400 Subject: [PATCH 02/11] add error for self-referential struct, add btree set of currently-resolving structs, add check for self in currently-resolving structs, throw error if so, update test program, wip cleanup --- Cargo.toml | 1 - .../src/hir/resolution/errors.rs | 9 + .../src/hir/resolution/resolver.rs | 44 +- .../noirc_frontend/src/hir/type_check/mod.rs | 41 +- compiler/noirc_frontend/src/tests.rs | 2380 ++++++++--------- .../self_referential_struct/src/main.nr | 14 +- 6 files changed, 1234 insertions(+), 1255 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cdbb40f630a..f333a43a1a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,6 @@ noir_lsp = { path = "tooling/lsp" } noir_debugger = { path = "tooling/debugger" } noirc_abi = { path = "tooling/noirc_abi" } bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } -acvm_cli = { path = "tooling/acvm_cli" } # LSP async-lsp = { version = "0.1.0", default-features = false } diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index 71e3f3482fc..d21c2651927 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -86,6 +86,8 @@ pub enum ResolverError { JumpInConstrainedFn { is_break: bool, span: Span }, #[error("break/continue are only allowed within loops")] JumpOutsideLoop { is_break: bool, span: Span }, + #[error("Self-referential structs are not supported")] + SelfReferentialStruct { span: Span }, } impl ResolverError { @@ -340,6 +342,13 @@ impl From for Diagnostic { span, ) }, + ResolverError::SelfReferentialStruct { span } => { + Diagnostic::simple_error( + "Self-referential structs are not supported".into(), + "".into(), + span, + ) + }, } } } diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index a047d1d4eb1..b4e0c0b2436 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -22,7 +22,7 @@ use crate::hir_def::traits::{Trait, TraitConstraint}; use crate::macros_api::SecondaryAttribute; use crate::token::{Attributes, FunctionAttribute}; use regex::Regex; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::rc::Rc; use crate::graph::CrateId; @@ -99,6 +99,9 @@ pub struct Resolver<'a> { /// Used to link items to their dependencies in the dependency graph current_item: Option, + /// In-resolution names + resolving_names: BTreeSet, + /// True if the current module is a contract. /// This is usually determined by self.path_resolver.module_id(), but it can /// be overridden for impls. Impls are an odd case since the methods within resolve @@ -162,6 +165,7 @@ impl<'a> Resolver<'a> { lambda_stack: Vec::new(), current_trait_impl: None, current_item: None, + resolving_names: BTreeSet::new(), file, in_contract, in_unconstrained_fn: false, @@ -507,13 +511,7 @@ impl<'a> Resolver<'a> { Unit => Type::Unit, Unspecified => Type::Error, Error => Type::Error, - Named(path, args, _) => { - // TODO: remove before PR - // dbg!("calling resolve_named_type.."); - let result = self.resolve_named_type(path, args, new_variables); - // dbg!("called resolve_named_type: {:?}", result.clone()); - result - }, + Named(path, args, _) => self.resolve_named_type(path, args, new_variables), TraitAsType(path, args) => self.resolve_trait_as_type(path, args, new_variables), Tuple(fields) => { @@ -572,11 +570,6 @@ impl<'a> Resolver<'a> { args: Vec, new_variables: &mut Generics, ) -> Type { - // TODO: remove before PR - // if self.current_item.is_some() { - // panic!("resolve_named_type: self {:?}, path {:?}, args {:?}, new vars {:?}", self.current_item, path.clone(), args.clone(), new_variables.clone()); - // } - if args.is_empty() { if let Some(typ) = self.lookup_generic_or_global_type(&path) { return typ; @@ -628,17 +621,16 @@ impl<'a> Resolver<'a> { return Type::Alias(alias, args); } - // TODO: remove before PR - // dbg!("structs: {:?}", &self.interner.structs); - if let Some(current_item_id) = self.current_item { - dbg!("dependency: {:?}", self.interner.get_or_insert_dependency(current_item_id)); - dbg!("dependency: {:?}", self.interner.check_for_dependency_cycles()); - } - dbg!("lookup_struct_or_error: self {:?}, path {:?}, args {:?}, new vars {:?}", self.current_item, path.clone(), args.clone(), new_variables.clone()); - dbg!("ok: {:?}", self.lookup_struct_or_error(path.clone())); - match self.lookup_struct_or_error(path) { Some(struct_type) => { + if self.resolving_names.contains(&struct_type.borrow().name) { + self.push_err(ResolverError::SelfReferentialStruct { + span: struct_type.borrow().name.span(), + }); + + return Type::Error; + } + let expected_generic_count = struct_type.borrow().generics.len(); if !self.in_contract && self @@ -903,18 +895,16 @@ impl<'a> Resolver<'a> { unresolved: NoirStruct, struct_id: StructId, ) -> (Generics, Vec<(Ident, Type)>, Vec) { - - dbg!("resolve_struct_fields: {:?}", unresolved.clone().name); - // dbg!("resolve_struct_fields: {:?}, {:?}, {:?}", &self.interner.structs, unresolved.clone(), struct_id); - panic!("resolve_struct_fields: {:?}, {:?}, {:?}", &self.interner.structs, unresolved, struct_id); - let generics = self.add_generics(&unresolved.generics); // Check whether the struct definition has globals in the local module and add them to the scope self.resolve_local_globals(); self.current_item = Some(DependencyId::Struct(struct_id)); + + self.resolving_names.insert(unresolved.name.clone()); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); + self.resolving_names.remove(&unresolved.name); (generics, fields, self.errors) } diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index e86226cfdf4..449b256b3d9 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -615,46 +615,27 @@ pub mod test { } #[test] - fn self_referential_struct() { + fn closure_with_no_args() { let src = r#" - struct Option { - _is_some: bool, - _value: T, - } - - impl Option { - /// Constructs a None value - pub fn none() -> Self { - Self { _is_some: false, _value: crate::unsafe::zeroed() } - } - } - - struct SelfReferential - { - prop : Option - } - - // #[test] - // unconstrained - // fn test_self_referential() - // { - // let self_ref = SelfReferential { prop : Option::none() }; - // } + fn main(x : Field) -> pub Field { + let closure = || x; + closure() + } "#; type_check_src_code(src, vec![String::from("main")]); } #[test] - fn closure_with_no_args() { + fn fold_entry_point() { let src = r#" - fn main(x : Field) -> pub Field { - let closure = || x; - closure() + #[fold] + fn fold(x: &mut Field) -> Field { + *x } - "#; + "#; - type_check_src_code(src, vec![String::from("main")]); + type_check_src_code_errors_expected(src, vec![String::from("fold")], 1); } #[test] diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index b6a4bf9ebac..53a6700362f 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -91,1195 +91,1195 @@ mod test { get_program(src).2 } -// #[test] -// fn check_trait_implemented_for_all_t() { -// let src = " -// trait Default { -// fn default() -> Self; -// } -// -// trait Eq { -// fn eq(self, other: Self) -> bool; -// } -// -// trait IsDefault { -// fn is_default(self) -> bool; -// } -// -// impl IsDefault for T where T: Default + Eq { -// fn is_default(self) -> bool { -// self.eq(T::default()) -// } -// } -// -// struct Foo { -// a: u64, -// } -// -// impl Eq for Foo { -// fn eq(self, other: Foo) -> bool { self.a == other.a } -// } -// -// impl Default for u64 { -// fn default() -> Self { -// 0 -// } -// } -// -// impl Default for Foo { -// fn default() -> Self { -// Foo { a: Default::default() } -// } -// } -// -// fn main(a: Foo) -> pub bool { -// a.is_default() -// }"; -// -// let errors = get_program_errors(src); -// errors.iter().for_each(|err| println!("{:?}", err)); -// assert!(errors.is_empty()); -// } -// -// #[test] -// fn check_trait_implementation_duplicate_method() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Field; -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// impl Default for Foo { -// // Duplicate trait methods should not compile -// fn default(x: Field, y: Field) -> Field { -// y + 2 * x -// } -// // Duplicate trait methods should not compile -// fn default(x: Field, y: Field) -> Field { -// x + 2 * y -// } -// } -// -// fn main() {}"; -// -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { -// typ, -// first_def, -// second_def, -// }) => { -// assert_eq!(typ, &DuplicateType::TraitAssociatedFunction); -// assert_eq!(first_def, "default"); -// assert_eq!(second_def, "default"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_method_return_type() { -// let src = " -// trait Default { -// fn default() -> Self; -// } -// -// struct Foo { -// } -// -// impl Default for Foo { -// fn default() -> Field { -// 0 -// } -// } -// -// fn main() { -// } -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::TypeError(TypeCheckError::TypeMismatch { -// expected_typ, -// expr_typ, -// expr_span: _, -// }) => { -// assert_eq!(expected_typ, "Foo"); -// assert_eq!(expr_typ, "Field"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_method_return_type2() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Self; -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// impl Default for Foo { -// fn default(x: Field, _y: Field) -> Field { -// x -// } -// } -// -// fn main() { -// }"; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::TypeError(TypeCheckError::TypeMismatch { -// expected_typ, -// expr_typ, -// expr_span: _, -// }) => { -// assert_eq!(expected_typ, "Foo"); -// assert_eq!(expr_typ, "Field"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_missing_implementation() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Self; -// -// fn method2(x: Field) -> Field; -// -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// impl Default for Foo { -// fn default(x: Field, y: Field) -> Self { -// Self { bar: x, array: [x,y] } -// } -// } -// -// fn main() { -// } -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::TraitMissingMethod { -// trait_name, -// method_name, -// trait_impl_span: _, -// }) => { -// assert_eq!(trait_name, "Default"); -// assert_eq!(method_name, "method2"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_not_in_scope() { -// let src = " -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// // Default trait does not exist -// impl Default for Foo { -// fn default(x: Field, y: Field) -> Self { -// Self { bar: x, array: [x,y] } -// } -// } -// -// fn main() { -// } -// -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::TraitNotFound { -// trait_path, -// }) => { -// assert_eq!(trait_path.as_string(), "Default"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_method_name() { -// let src = " -// trait Default { -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// // wrong trait name method should not compile -// impl Default for Foo { -// fn does_not_exist(x: Field, y: Field) -> Self { -// Self { bar: x, array: [x,y] } -// } -// } -// -// fn main() { -// }"; -// let compilation_errors = get_program_errors(src); -// assert!(!has_parser_error(&compilation_errors)); -// assert!( -// compilation_errors.len() == 1, -// "Expected 1 compilation error, got: {:?}", -// compilation_errors -// ); -// -// for (err, _file_id) in compilation_errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::MethodNotInTrait { -// trait_name, -// impl_method, -// }) => { -// assert_eq!(trait_name, "Default"); -// assert_eq!(impl_method, "does_not_exist"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_parameter() { -// let src = " -// trait Default { -// fn default(x: Field) -> Self; -// } -// -// struct Foo { -// bar: u32, -// } -// -// impl Default for Foo { -// fn default(x: u32) -> Self { -// Foo {bar: x} -// } -// } -// -// fn main() { -// } -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { -// method_name, -// expected_typ, -// actual_typ, -// .. -// }) => { -// assert_eq!(method_name, "default"); -// assert_eq!(expected_typ, "Field"); -// assert_eq!(actual_typ, "u32"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_parameter2() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Self; -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// impl Default for Foo { -// fn default(x: Field, y: Foo) -> Self { -// Self { bar: x, array: [x, y.bar] } -// } -// } -// -// fn main() { -// }"; -// -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { -// method_name, -// expected_typ, -// actual_typ, -// .. -// }) => { -// assert_eq!(method_name, "default"); -// assert_eq!(expected_typ, "Field"); -// assert_eq!(actual_typ, "Foo"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_parameter_type() { -// let src = " -// trait Default { -// fn default(x: Field, y: NotAType) -> Field; -// } -// -// fn main(x: Field, y: Field) { -// assert(y == x); -// }"; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::ResolverError(ResolverError::PathResolutionError( -// PathResolutionError::Unresolved(ident), -// )) => { -// assert_eq!(ident, "NotAType"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_wrong_parameters_count() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Self; -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// impl Default for Foo { -// fn default(x: Field) -> Self { -// Self { bar: x, array: [x, x] } -// } -// } -// -// fn main() { -// } -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::TypeError(TypeCheckError::MismatchTraitImplNumParameters { -// actual_num_parameters, -// expected_num_parameters, -// trait_name, -// method_name, -// .. -// }) => { -// assert_eq!(actual_num_parameters, &1_usize); -// assert_eq!(expected_num_parameters, &2_usize); -// assert_eq!(method_name, "default"); -// assert_eq!(trait_name, "Default"); -// } -// _ => { -// panic!("No other errors are expected in this test case! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_impl_for_non_type() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Field; -// } -// -// impl Default for main { -// fn default(x: Field, y: Field) -> Field { -// x + y -// } -// } -// -// fn main() {} -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::ResolverError(ResolverError::Expected { -// expected, got, .. -// }) => { -// assert_eq!(expected, "type"); -// assert_eq!(got, "function"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_impl_struct_not_trait() { -// let src = " -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// struct Default { -// x: Field, -// z: Field, -// } -// -// // Default is struct not a trait -// impl Default for Foo { -// fn default(x: Field, y: Field) -> Self { -// Self { bar: x, array: [x,y] } -// } -// } -// -// fn main() { -// } -// -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::NotATrait { -// not_a_trait_name, -// }) => { -// assert_eq!(not_a_trait_name.to_string(), "plain::Default"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_duplicate_declaration() { -// let src = " -// trait Default { -// fn default(x: Field, y: Field) -> Self; -// } -// -// struct Foo { -// bar: Field, -// array: [Field; 2], -// } -// -// impl Default for Foo { -// fn default(x: Field,y: Field) -> Self { -// Self { bar: x, array: [x,y] } -// } -// } -// -// -// trait Default { -// fn default(x: Field) -> Self; -// } -// -// fn main() { -// }"; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { -// typ, -// first_def, -// second_def, -// }) => { -// assert_eq!(typ, &DuplicateType::Trait); -// assert_eq!(first_def, "Default"); -// assert_eq!(second_def, "Default"); -// } -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_duplicate_implementation() { -// let src = " -// trait Default { -// } -// struct Foo { -// bar: Field, -// } -// -// impl Default for Foo { -// } -// impl Default for Foo { -// } -// fn main() { -// } -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { -// .. -// }) => (), -// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { -// .. -// }) => (), -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// #[test] -// fn check_trait_duplicate_implementation_with_alias() { -// let src = " -// trait Default { -// } -// -// struct MyStruct { -// } -// -// type MyType = MyStruct; -// -// impl Default for MyStruct { -// } -// -// impl Default for MyType { -// } -// -// fn main() { -// } -// "; -// let errors = get_program_errors(src); -// assert!(!has_parser_error(&errors)); -// assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); -// for (err, _file_id) in errors { -// match &err { -// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { -// .. -// }) => (), -// CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { -// .. -// }) => (), -// _ => { -// panic!("No other errors are expected! Found = {:?}", err); -// } -// }; -// } -// } -// -// fn get_program_captures(src: &str) -> Vec> { -// let (program, context, _errors) = get_program(src); -// let interner = context.def_interner; -// let mut all_captures: Vec> = Vec::new(); -// for func in program.into_sorted().functions { -// let func_id = interner.find_function(func.name()).unwrap(); -// let hir_func = interner.function(&func_id); -// // Iterate over function statements and apply filtering function -// find_lambda_captures( -// hir_func.block(&interner).statements(), -// &interner, -// &mut all_captures, -// ); -// } -// all_captures -// } -// -// fn find_lambda_captures( -// stmts: &[StmtId], -// interner: &NodeInterner, -// result: &mut Vec>, -// ) { -// for stmt_id in stmts.iter() { -// let hir_stmt = interner.statement(stmt_id); -// let expr_id = match hir_stmt { -// HirStatement::Expression(expr_id) => expr_id, -// HirStatement::Let(let_stmt) => let_stmt.expression, -// HirStatement::Assign(assign_stmt) => assign_stmt.expression, -// HirStatement::Constrain(constr_stmt) => constr_stmt.0, -// HirStatement::Semi(semi_expr) => semi_expr, -// HirStatement::For(for_loop) => for_loop.block, -// HirStatement::Error => panic!("Invalid HirStatement!"), -// HirStatement::Break => panic!("Unexpected break"), -// HirStatement::Continue => panic!("Unexpected continue"), -// }; -// let expr = interner.expression(&expr_id); -// -// get_lambda_captures(expr, interner, result); // TODO: dyn filter function as parameter -// } -// } -// -// fn get_lambda_captures( -// expr: HirExpression, -// interner: &NodeInterner, -// result: &mut Vec>, -// ) { -// if let HirExpression::Lambda(lambda_expr) = expr { -// let mut cur_capture = Vec::new(); -// -// for capture in lambda_expr.captures.iter() { -// cur_capture.push(interner.definition(capture.ident.id).name.clone()); -// } -// result.push(cur_capture); -// -// // Check for other captures recursively within the lambda body -// let hir_body_expr = interner.expression(&lambda_expr.body); -// if let HirExpression::Block(block_expr) = hir_body_expr { -// find_lambda_captures(block_expr.statements(), interner, result); -// } -// } -// } -// -// #[test] -// fn resolve_empty_function() { -// let src = " -// fn main() { -// -// } -// "; -// assert!(get_program_errors(src).is_empty()); -// } -// #[test] -// fn resolve_basic_function() { -// let src = r#" -// fn main(x : Field) { -// let y = x + x; -// assert(y == x); -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// #[test] -// fn resolve_unused_var() { -// let src = r#" -// fn main(x : Field) { -// let y = x + x; -// assert(x == x); -// } -// "#; -// -// let errors = get_program_errors(src); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// // It should be regarding the unused variable -// match &errors[0].0 { -// CompilationError::ResolverError(ResolverError::UnusedVariable { ident }) => { -// assert_eq!(&ident.0.contents, "y"); -// } -// _ => unreachable!("we should only have an unused var error"), -// } -// } -// -// #[test] -// fn resolve_unresolved_var() { -// let src = r#" -// fn main(x : Field) { -// let y = x + x; -// assert(y == z); -// } -// "#; -// let errors = get_program_errors(src); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// // It should be regarding the unresolved var `z` (Maybe change to undeclared and special case) -// match &errors[0].0 { -// CompilationError::ResolverError(ResolverError::VariableNotDeclared { -// name, -// span: _, -// }) => assert_eq!(name, "z"), -// _ => unimplemented!("we should only have an unresolved variable"), -// } -// } -// -// #[test] -// fn unresolved_path() { -// let src = " -// fn main(x : Field) { -// let _z = some::path::to::a::func(x); -// } -// "; -// let errors = get_program_errors(src); -// assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); -// for (compilation_error, _file_id) in errors { -// match compilation_error { -// CompilationError::ResolverError(err) => { -// match err { -// ResolverError::PathResolutionError(PathResolutionError::Unresolved( -// name, -// )) => { -// assert_eq!(name.to_string(), "some"); -// } -// _ => unimplemented!("we should only have an unresolved function"), -// }; -// } -// _ => unimplemented!(), -// } -// } -// } -// -// #[test] -// fn resolve_literal_expr() { -// let src = r#" -// fn main(x : Field) { -// let y = 5; -// assert(y == x); -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// -// #[test] -// fn multiple_resolution_errors() { -// let src = r#" -// fn main(x : Field) { -// let y = foo::bar(x); -// let z = y + a; -// } -// "#; -// -// let errors = get_program_errors(src); -// assert!(errors.len() == 3, "Expected 3 errors, got: {:?}", errors); -// -// // Errors are: -// // `a` is undeclared -// // `z` is unused -// // `foo::bar` does not exist -// for (compilation_error, _file_id) in errors { -// match compilation_error { -// CompilationError::ResolverError(err) => { -// match err { -// ResolverError::UnusedVariable { ident } => { -// assert_eq!(&ident.0.contents, "z"); -// } -// ResolverError::VariableNotDeclared { name, .. } => { -// assert_eq!(name, "a"); -// } -// ResolverError::PathResolutionError(PathResolutionError::Unresolved( -// name, -// )) => { -// assert_eq!(name.to_string(), "foo"); -// } -// _ => unimplemented!(), -// }; -// } -// _ => unimplemented!(), -// } -// } -// } -// -// #[test] -// fn resolve_prefix_expr() { -// let src = r#" -// fn main(x : Field) { -// let _y = -x; -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// -// #[test] -// fn resolve_for_expr() { -// let src = r#" -// fn main(x : u64) { -// for i in 1..20 { -// let _z = x + i; -// }; -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// -// #[test] -// fn resolve_call_expr() { -// let src = r#" -// fn main(x : Field) { -// let _z = foo(x); -// } -// -// fn foo(x : Field) -> Field { -// x -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// -// #[test] -// fn resolve_shadowing() { -// let src = r#" -// fn main(x : Field) { -// let x = foo(x); -// let x = x; -// let (x, x) = (x, x); -// let _ = x; -// } -// -// fn foo(x : Field) -> Field { -// x -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// -// #[test] -// fn resolve_basic_closure() { -// let src = r#" -// fn main(x : Field) -> pub Field { -// let closure = |y| y + x; -// closure(x) -// } -// "#; -// assert!(get_program_errors(src).is_empty()); -// } -// -// #[test] -// fn resolve_simplified_closure() { -// // based on bug https://github.com/noir-lang/noir/issues/1088 -// -// let src = r#"fn do_closure(x: Field) -> Field { -// let y = x; -// let ret_capture = || { -// y -// }; -// ret_capture() -// } -// -// fn main(x: Field) { -// assert(do_closure(x) == 100); -// } -// -// "#; -// let parsed_captures = get_program_captures(src); -// let expected_captures = vec![vec!["y".to_string()]]; -// assert_eq!(expected_captures, parsed_captures); -// } -// -// #[test] -// fn resolve_complex_closures() { -// let src = r#" -// fn main(x: Field) -> pub Field { -// let closure_without_captures = |x: Field| -> Field { x + x }; -// let a = closure_without_captures(1); -// -// let closure_capturing_a_param = |y: Field| -> Field { y + x }; -// let b = closure_capturing_a_param(2); -// -// let closure_capturing_a_local_var = |y: Field| -> Field { y + b }; -// let c = closure_capturing_a_local_var(3); -// -// let closure_with_transitive_captures = |y: Field| -> Field { -// let d = 5; -// let nested_closure = |z: Field| -> Field { -// let doubly_nested_closure = |w: Field| -> Field { w + x + b }; -// a + z + y + d + x + doubly_nested_closure(4) + x + y -// }; -// let res = nested_closure(5); -// res -// }; -// -// a + b + c + closure_with_transitive_captures(6) -// } -// "#; -// assert!(get_program_errors(src).is_empty(), "there should be no errors"); -// -// let expected_captures = vec![ -// vec![], -// vec!["x".to_string()], -// vec!["b".to_string()], -// vec!["x".to_string(), "b".to_string(), "a".to_string()], -// vec![ -// "x".to_string(), -// "b".to_string(), -// "a".to_string(), -// "y".to_string(), -// "d".to_string(), -// ], -// vec!["x".to_string(), "b".to_string()], -// ]; -// -// let parsed_captures = get_program_captures(src); -// -// assert_eq!(expected_captures, parsed_captures); -// } -// -// #[test] -// fn resolve_fmt_strings() { -// let src = r#" -// fn main() { -// let string = f"this is i: {i}"; -// println(string); -// -// println(f"I want to print {0}"); -// -// let new_val = 10; -// println(f"random_string{new_val}{new_val}"); -// } -// fn println(x : T) -> T { -// x -// } -// "#; -// -// let errors = get_program_errors(src); -// assert!(errors.len() == 5, "Expected 5 errors, got: {:?}", errors); -// -// for (err, _file_id) in errors { -// match &err { -// CompilationError::ResolverError(ResolverError::VariableNotDeclared { -// name, -// .. -// }) => { -// assert_eq!(name, "i"); -// } -// CompilationError::ResolverError(ResolverError::NumericConstantInFormatString { -// name, -// .. -// }) => { -// assert_eq!(name, "0"); -// } -// CompilationError::TypeError(TypeCheckError::UnusedResultError { -// expr_type: _, -// expr_span, -// }) => { -// let a = src.get(expr_span.start() as usize..expr_span.end() as usize).unwrap(); -// assert!( -// a == "println(string)" -// || a == "println(f\"I want to print {0}\")" -// || a == "println(f\"random_string{new_val}{new_val}\")" -// ); -// } -// _ => unimplemented!(), -// }; -// } -// } -// -// fn check_rewrite(src: &str, expected: &str) { -// let (_program, mut context, _errors) = get_program(src); -// let main_func_id = context.def_interner.find_function("main").unwrap(); -// let program = monomorphize(main_func_id, &mut context.def_interner).unwrap(); -// assert!(format!("{}", program) == expected); -// } -// -// #[test] -// fn simple_closure_with_no_captured_variables() { -// let src = r#" -// fn main() -> pub Field { -// let x = 1; -// let closure = || x; -// closure() -// } -// "#; -// -// let expected_rewrite = r#"fn main$f0() -> Field { -// let x$0 = 1; -// let closure$3 = { -// let closure_variable$2 = { -// let env$1 = (x$l0); -// (env$l1, lambda$f1) -// }; -// closure_variable$l2 -// }; -// { -// let tmp$4 = closure$l3; -// tmp$l4.1(tmp$l4.0) -// } -// } -// fn lambda$f1(mut env$l1: (Field)) -> Field { -// env$l1.0 -// } -// "#; -// check_rewrite(src, expected_rewrite); -// } -// -// #[test] -// fn deny_mutually_recursive_structs() { -// let src = r#" -// struct Foo { bar: Bar } -// struct Bar { foo: Foo } -// fn main() {} -// "#; -// assert_eq!(get_program_errors(src).len(), 1); -// } -// -// #[test] -// fn deny_cyclic_globals() { -// let src = r#" -// global A = B; -// global B = A; -// fn main() {} -// "#; -// assert_eq!(get_program_errors(src).len(), 1); -// } -// -// #[test] -// fn deny_cyclic_type_aliases() { -// let src = r#" -// type A = B; -// type B = A; -// fn main() {} -// "#; -// assert_eq!(get_program_errors(src).len(), 1); -// } -// -// #[test] -// fn ensure_nested_type_aliases_type_check() { -// let src = r#" -// type A = B; -// type B = u8; -// fn main() { -// let _a: A = 0 as u16; -// } -// "#; -// assert_eq!(get_program_errors(src).len(), 1); -// } -// -// #[test] -// fn type_aliases_in_entry_point() { -// let src = r#" -// type Foo = u8; -// fn main(_x: Foo) {} -// "#; -// assert_eq!(get_program_errors(src).len(), 0); -// } -// -// #[test] -// fn operators_in_global_used_in_type() { -// let src = r#" -// global ONE = 1; -// global COUNT = ONE + 2; -// fn main() { -// let _array: [Field; COUNT] = [1, 2, 3]; -// } -// "#; -// assert_eq!(get_program_errors(src).len(), 0); -// } -// -// #[test] -// fn break_and_continue_in_constrained_fn() { -// let src = r#" -// fn main() { -// for i in 0 .. 10 { -// if i == 2 { -// continue; -// } -// if i == 5 { -// break; -// } -// } -// } -// "#; -// assert_eq!(get_program_errors(src).len(), 2); -// } -// -// #[test] -// fn break_and_continue_outside_loop() { -// let src = r#" -// unconstrained fn main() { -// continue; -// break; -// } -// "#; -// assert_eq!(get_program_errors(src).len(), 2); -// } -// -// // Regression for #2540 -// #[test] -// fn for_loop_over_array() { -// let src = r#" -// fn hello(_array: [u1; N]) { -// for _ in 0..N {} -// } -// -// fn main() { -// let array: [u1; 2] = [0, 1]; -// hello(array); -// } -// "#; -// assert_eq!(get_program_errors(src).len(), 0); -// } -// -// // Regression for #4545 -// #[test] -// fn type_aliases_in_main() { -// let src = r#" -// type Outer = [u8; N]; -// fn main(_arg: Outer<1>) {} -// "#; -// assert_eq!(get_program_errors(src).len(), 0); -// } + #[test] + fn check_trait_implemented_for_all_t() { + let src = " + trait Default { + fn default() -> Self; + } + + trait Eq { + fn eq(self, other: Self) -> bool; + } + + trait IsDefault { + fn is_default(self) -> bool; + } + + impl IsDefault for T where T: Default + Eq { + fn is_default(self) -> bool { + self.eq(T::default()) + } + } + + struct Foo { + a: u64, + } + + impl Eq for Foo { + fn eq(self, other: Foo) -> bool { self.a == other.a } + } + + impl Default for u64 { + fn default() -> Self { + 0 + } + } + + impl Default for Foo { + fn default() -> Self { + Foo { a: Default::default() } + } + } + + fn main(a: Foo) -> pub bool { + a.is_default() + }"; + + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + + #[test] + fn check_trait_implementation_duplicate_method() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Field; + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + // Duplicate trait methods should not compile + fn default(x: Field, y: Field) -> Field { + y + 2 * x + } + // Duplicate trait methods should not compile + fn default(x: Field, y: Field) -> Field { + x + 2 * y + } + } + + fn main() {}"; + + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { + typ, + first_def, + second_def, + }) => { + assert_eq!(typ, &DuplicateType::TraitAssociatedFunction); + assert_eq!(first_def, "default"); + assert_eq!(second_def, "default"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_method_return_type() { + let src = " + trait Default { + fn default() -> Self; + } + + struct Foo { + } + + impl Default for Foo { + fn default() -> Field { + 0 + } + } + + fn main() { + } + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::TypeError(TypeCheckError::TypeMismatch { + expected_typ, + expr_typ, + expr_span: _, + }) => { + assert_eq!(expected_typ, "Foo"); + assert_eq!(expr_typ, "Field"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_method_return_type2() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Self; + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + fn default(x: Field, _y: Field) -> Field { + x + } + } + + fn main() { + }"; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::TypeError(TypeCheckError::TypeMismatch { + expected_typ, + expr_typ, + expr_span: _, + }) => { + assert_eq!(expected_typ, "Foo"); + assert_eq!(expr_typ, "Field"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_missing_implementation() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Self; + + fn method2(x: Field) -> Field; + + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + fn default(x: Field, y: Field) -> Self { + Self { bar: x, array: [x,y] } + } + } + + fn main() { + } + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::TraitMissingMethod { + trait_name, + method_name, + trait_impl_span: _, + }) => { + assert_eq!(trait_name, "Default"); + assert_eq!(method_name, "method2"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_not_in_scope() { + let src = " + struct Foo { + bar: Field, + array: [Field; 2], + } + + // Default trait does not exist + impl Default for Foo { + fn default(x: Field, y: Field) -> Self { + Self { bar: x, array: [x,y] } + } + } + + fn main() { + } + + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::TraitNotFound { + trait_path, + }) => { + assert_eq!(trait_path.as_string(), "Default"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_method_name() { + let src = " + trait Default { + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + // wrong trait name method should not compile + impl Default for Foo { + fn does_not_exist(x: Field, y: Field) -> Self { + Self { bar: x, array: [x,y] } + } + } + + fn main() { + }"; + let compilation_errors = get_program_errors(src); + assert!(!has_parser_error(&compilation_errors)); + assert!( + compilation_errors.len() == 1, + "Expected 1 compilation error, got: {:?}", + compilation_errors + ); + + for (err, _file_id) in compilation_errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::MethodNotInTrait { + trait_name, + impl_method, + }) => { + assert_eq!(trait_name, "Default"); + assert_eq!(impl_method, "does_not_exist"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_parameter() { + let src = " + trait Default { + fn default(x: Field) -> Self; + } + + struct Foo { + bar: u32, + } + + impl Default for Foo { + fn default(x: u32) -> Self { + Foo {bar: x} + } + } + + fn main() { + } + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { + method_name, + expected_typ, + actual_typ, + .. + }) => { + assert_eq!(method_name, "default"); + assert_eq!(expected_typ, "Field"); + assert_eq!(actual_typ, "u32"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_parameter2() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Self; + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + fn default(x: Field, y: Foo) -> Self { + Self { bar: x, array: [x, y.bar] } + } + } + + fn main() { + }"; + + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::TypeError(TypeCheckError::TraitMethodParameterTypeMismatch { + method_name, + expected_typ, + actual_typ, + .. + }) => { + assert_eq!(method_name, "default"); + assert_eq!(expected_typ, "Field"); + assert_eq!(actual_typ, "Foo"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_parameter_type() { + let src = " + trait Default { + fn default(x: Field, y: NotAType) -> Field; + } + + fn main(x: Field, y: Field) { + assert(y == x); + }"; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::ResolverError(ResolverError::PathResolutionError( + PathResolutionError::Unresolved(ident), + )) => { + assert_eq!(ident, "NotAType"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_wrong_parameters_count() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Self; + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + fn default(x: Field) -> Self { + Self { bar: x, array: [x, x] } + } + } + + fn main() { + } + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::TypeError(TypeCheckError::MismatchTraitImplNumParameters { + actual_num_parameters, + expected_num_parameters, + trait_name, + method_name, + .. + }) => { + assert_eq!(actual_num_parameters, &1_usize); + assert_eq!(expected_num_parameters, &2_usize); + assert_eq!(method_name, "default"); + assert_eq!(trait_name, "Default"); + } + _ => { + panic!("No other errors are expected in this test case! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_impl_for_non_type() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Field; + } + + impl Default for main { + fn default(x: Field, y: Field) -> Field { + x + y + } + } + + fn main() {} + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::ResolverError(ResolverError::Expected { + expected, got, .. + }) => { + assert_eq!(expected, "type"); + assert_eq!(got, "function"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_impl_struct_not_trait() { + let src = " + struct Foo { + bar: Field, + array: [Field; 2], + } + + struct Default { + x: Field, + z: Field, + } + + // Default is struct not a trait + impl Default for Foo { + fn default(x: Field, y: Field) -> Self { + Self { bar: x, array: [x,y] } + } + } + + fn main() { + } + + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::NotATrait { + not_a_trait_name, + }) => { + assert_eq!(not_a_trait_name.to_string(), "plain::Default"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_duplicate_declaration() { + let src = " + trait Default { + fn default(x: Field, y: Field) -> Self; + } + + struct Foo { + bar: Field, + array: [Field; 2], + } + + impl Default for Foo { + fn default(x: Field,y: Field) -> Self { + Self { bar: x, array: [x,y] } + } + } + + + trait Default { + fn default(x: Field) -> Self; + } + + fn main() { + }"; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { + typ, + first_def, + second_def, + }) => { + assert_eq!(typ, &DuplicateType::Trait); + assert_eq!(first_def, "Default"); + assert_eq!(second_def, "Default"); + } + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_duplicate_implementation() { + let src = " + trait Default { + } + struct Foo { + bar: Field, + } + + impl Default for Foo { + } + impl Default for Foo { + } + fn main() { + } + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { + .. + }) => (), + CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { + .. + }) => (), + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + #[test] + fn check_trait_duplicate_implementation_with_alias() { + let src = " + trait Default { + } + + struct MyStruct { + } + + type MyType = MyStruct; + + impl Default for MyStruct { + } + + impl Default for MyType { + } + + fn main() { + } + "; + let errors = get_program_errors(src); + assert!(!has_parser_error(&errors)); + assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); + for (err, _file_id) in errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImpl { + .. + }) => (), + CompilationError::DefinitionError(DefCollectorErrorKind::OverlappingImplNote { + .. + }) => (), + _ => { + panic!("No other errors are expected! Found = {:?}", err); + } + }; + } + } + + fn get_program_captures(src: &str) -> Vec> { + let (program, context, _errors) = get_program(src); + let interner = context.def_interner; + let mut all_captures: Vec> = Vec::new(); + for func in program.into_sorted().functions { + let func_id = interner.find_function(func.name()).unwrap(); + let hir_func = interner.function(&func_id); + // Iterate over function statements and apply filtering function + find_lambda_captures( + hir_func.block(&interner).statements(), + &interner, + &mut all_captures, + ); + } + all_captures + } + + fn find_lambda_captures( + stmts: &[StmtId], + interner: &NodeInterner, + result: &mut Vec>, + ) { + for stmt_id in stmts.iter() { + let hir_stmt = interner.statement(stmt_id); + let expr_id = match hir_stmt { + HirStatement::Expression(expr_id) => expr_id, + HirStatement::Let(let_stmt) => let_stmt.expression, + HirStatement::Assign(assign_stmt) => assign_stmt.expression, + HirStatement::Constrain(constr_stmt) => constr_stmt.0, + HirStatement::Semi(semi_expr) => semi_expr, + HirStatement::For(for_loop) => for_loop.block, + HirStatement::Error => panic!("Invalid HirStatement!"), + HirStatement::Break => panic!("Unexpected break"), + HirStatement::Continue => panic!("Unexpected continue"), + }; + let expr = interner.expression(&expr_id); + + get_lambda_captures(expr, interner, result); // TODO: dyn filter function as parameter + } + } + + fn get_lambda_captures( + expr: HirExpression, + interner: &NodeInterner, + result: &mut Vec>, + ) { + if let HirExpression::Lambda(lambda_expr) = expr { + let mut cur_capture = Vec::new(); + + for capture in lambda_expr.captures.iter() { + cur_capture.push(interner.definition(capture.ident.id).name.clone()); + } + result.push(cur_capture); + + // Check for other captures recursively within the lambda body + let hir_body_expr = interner.expression(&lambda_expr.body); + if let HirExpression::Block(block_expr) = hir_body_expr { + find_lambda_captures(block_expr.statements(), interner, result); + } + } + } + + #[test] + fn resolve_empty_function() { + let src = " + fn main() { + + } + "; + assert!(get_program_errors(src).is_empty()); + } + #[test] + fn resolve_basic_function() { + let src = r#" + fn main(x : Field) { + let y = x + x; + assert(y == x); + } + "#; + assert!(get_program_errors(src).is_empty()); + } + #[test] + fn resolve_unused_var() { + let src = r#" + fn main(x : Field) { + let y = x + x; + assert(x == x); + } + "#; + + let errors = get_program_errors(src); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + // It should be regarding the unused variable + match &errors[0].0 { + CompilationError::ResolverError(ResolverError::UnusedVariable { ident }) => { + assert_eq!(&ident.0.contents, "y"); + } + _ => unreachable!("we should only have an unused var error"), + } + } + + #[test] + fn resolve_unresolved_var() { + let src = r#" + fn main(x : Field) { + let y = x + x; + assert(y == z); + } + "#; + let errors = get_program_errors(src); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + // It should be regarding the unresolved var `z` (Maybe change to undeclared and special case) + match &errors[0].0 { + CompilationError::ResolverError(ResolverError::VariableNotDeclared { + name, + span: _, + }) => assert_eq!(name, "z"), + _ => unimplemented!("we should only have an unresolved variable"), + } + } + + #[test] + fn unresolved_path() { + let src = " + fn main(x : Field) { + let _z = some::path::to::a::func(x); + } + "; + let errors = get_program_errors(src); + assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); + for (compilation_error, _file_id) in errors { + match compilation_error { + CompilationError::ResolverError(err) => { + match err { + ResolverError::PathResolutionError(PathResolutionError::Unresolved( + name, + )) => { + assert_eq!(name.to_string(), "some"); + } + _ => unimplemented!("we should only have an unresolved function"), + }; + } + _ => unimplemented!(), + } + } + } + + #[test] + fn resolve_literal_expr() { + let src = r#" + fn main(x : Field) { + let y = 5; + assert(y == x); + } + "#; + assert!(get_program_errors(src).is_empty()); + } + + #[test] + fn multiple_resolution_errors() { + let src = r#" + fn main(x : Field) { + let y = foo::bar(x); + let z = y + a; + } + "#; + + let errors = get_program_errors(src); + assert!(errors.len() == 3, "Expected 3 errors, got: {:?}", errors); + + // Errors are: + // `a` is undeclared + // `z` is unused + // `foo::bar` does not exist + for (compilation_error, _file_id) in errors { + match compilation_error { + CompilationError::ResolverError(err) => { + match err { + ResolverError::UnusedVariable { ident } => { + assert_eq!(&ident.0.contents, "z"); + } + ResolverError::VariableNotDeclared { name, .. } => { + assert_eq!(name, "a"); + } + ResolverError::PathResolutionError(PathResolutionError::Unresolved( + name, + )) => { + assert_eq!(name.to_string(), "foo"); + } + _ => unimplemented!(), + }; + } + _ => unimplemented!(), + } + } + } + + #[test] + fn resolve_prefix_expr() { + let src = r#" + fn main(x : Field) { + let _y = -x; + } + "#; + assert!(get_program_errors(src).is_empty()); + } + + #[test] + fn resolve_for_expr() { + let src = r#" + fn main(x : u64) { + for i in 1..20 { + let _z = x + i; + }; + } + "#; + assert!(get_program_errors(src).is_empty()); + } + + #[test] + fn resolve_call_expr() { + let src = r#" + fn main(x : Field) { + let _z = foo(x); + } + + fn foo(x : Field) -> Field { + x + } + "#; + assert!(get_program_errors(src).is_empty()); + } + + #[test] + fn resolve_shadowing() { + let src = r#" + fn main(x : Field) { + let x = foo(x); + let x = x; + let (x, x) = (x, x); + let _ = x; + } + + fn foo(x : Field) -> Field { + x + } + "#; + assert!(get_program_errors(src).is_empty()); + } + + #[test] + fn resolve_basic_closure() { + let src = r#" + fn main(x : Field) -> pub Field { + let closure = |y| y + x; + closure(x) + } + "#; + assert!(get_program_errors(src).is_empty()); + } + + #[test] + fn resolve_simplified_closure() { + // based on bug https://github.com/noir-lang/noir/issues/1088 + + let src = r#"fn do_closure(x: Field) -> Field { + let y = x; + let ret_capture = || { + y + }; + ret_capture() + } + + fn main(x: Field) { + assert(do_closure(x) == 100); + } + + "#; + let parsed_captures = get_program_captures(src); + let expected_captures = vec![vec!["y".to_string()]]; + assert_eq!(expected_captures, parsed_captures); + } + + #[test] + fn resolve_complex_closures() { + let src = r#" + fn main(x: Field) -> pub Field { + let closure_without_captures = |x: Field| -> Field { x + x }; + let a = closure_without_captures(1); + + let closure_capturing_a_param = |y: Field| -> Field { y + x }; + let b = closure_capturing_a_param(2); + + let closure_capturing_a_local_var = |y: Field| -> Field { y + b }; + let c = closure_capturing_a_local_var(3); + + let closure_with_transitive_captures = |y: Field| -> Field { + let d = 5; + let nested_closure = |z: Field| -> Field { + let doubly_nested_closure = |w: Field| -> Field { w + x + b }; + a + z + y + d + x + doubly_nested_closure(4) + x + y + }; + let res = nested_closure(5); + res + }; + + a + b + c + closure_with_transitive_captures(6) + } + "#; + assert!(get_program_errors(src).is_empty(), "there should be no errors"); + + let expected_captures = vec![ + vec![], + vec!["x".to_string()], + vec!["b".to_string()], + vec!["x".to_string(), "b".to_string(), "a".to_string()], + vec![ + "x".to_string(), + "b".to_string(), + "a".to_string(), + "y".to_string(), + "d".to_string(), + ], + vec!["x".to_string(), "b".to_string()], + ]; + + let parsed_captures = get_program_captures(src); + + assert_eq!(expected_captures, parsed_captures); + } + + #[test] + fn resolve_fmt_strings() { + let src = r#" + fn main() { + let string = f"this is i: {i}"; + println(string); + + println(f"I want to print {0}"); + + let new_val = 10; + println(f"random_string{new_val}{new_val}"); + } + fn println(x : T) -> T { + x + } + "#; + + let errors = get_program_errors(src); + assert!(errors.len() == 5, "Expected 5 errors, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::ResolverError(ResolverError::VariableNotDeclared { + name, + .. + }) => { + assert_eq!(name, "i"); + } + CompilationError::ResolverError(ResolverError::NumericConstantInFormatString { + name, + .. + }) => { + assert_eq!(name, "0"); + } + CompilationError::TypeError(TypeCheckError::UnusedResultError { + expr_type: _, + expr_span, + }) => { + let a = src.get(expr_span.start() as usize..expr_span.end() as usize).unwrap(); + assert!( + a == "println(string)" + || a == "println(f\"I want to print {0}\")" + || a == "println(f\"random_string{new_val}{new_val}\")" + ); + } + _ => unimplemented!(), + }; + } + } + + fn check_rewrite(src: &str, expected: &str) { + let (_program, mut context, _errors) = get_program(src); + let main_func_id = context.def_interner.find_function("main").unwrap(); + let program = monomorphize(main_func_id, &mut context.def_interner).unwrap(); + assert!(format!("{}", program) == expected); + } + + #[test] + fn simple_closure_with_no_captured_variables() { + let src = r#" + fn main() -> pub Field { + let x = 1; + let closure = || x; + closure() + } + "#; + + let expected_rewrite = r#"fn main$f0() -> Field { + let x$0 = 1; + let closure$3 = { + let closure_variable$2 = { + let env$1 = (x$l0); + (env$l1, lambda$f1) + }; + closure_variable$l2 + }; + { + let tmp$4 = closure$l3; + tmp$l4.1(tmp$l4.0) + } +} +fn lambda$f1(mut env$l1: (Field)) -> Field { + env$l1.0 +} +"#; + check_rewrite(src, expected_rewrite); + } + + #[test] + fn deny_mutually_recursive_structs() { + let src = r#" + struct Foo { bar: Bar } + struct Bar { foo: Foo } + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } + + #[test] + fn deny_cyclic_globals() { + let src = r#" + global A = B; + global B = A; + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } + + #[test] + fn deny_cyclic_type_aliases() { + let src = r#" + type A = B; + type B = A; + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } + + #[test] + fn ensure_nested_type_aliases_type_check() { + let src = r#" + type A = B; + type B = u8; + fn main() { + let _a: A = 0 as u16; + } + "#; + assert_eq!(get_program_errors(src).len(), 1); + } + + #[test] + fn type_aliases_in_entry_point() { + let src = r#" + type Foo = u8; + fn main(_x: Foo) {} + "#; + assert_eq!(get_program_errors(src).len(), 0); + } + + #[test] + fn operators_in_global_used_in_type() { + let src = r#" + global ONE = 1; + global COUNT = ONE + 2; + fn main() { + let _array: [Field; COUNT] = [1, 2, 3]; + } + "#; + assert_eq!(get_program_errors(src).len(), 0); + } + + #[test] + fn break_and_continue_in_constrained_fn() { + let src = r#" + fn main() { + for i in 0 .. 10 { + if i == 2 { + continue; + } + if i == 5 { + break; + } + } + } + "#; + assert_eq!(get_program_errors(src).len(), 2); + } + + #[test] + fn break_and_continue_outside_loop() { + let src = r#" + unconstrained fn main() { + continue; + break; + } + "#; + assert_eq!(get_program_errors(src).len(), 2); + } + + // Regression for #2540 + #[test] + fn for_loop_over_array() { + let src = r#" + fn hello(_array: [u1; N]) { + for _ in 0..N {} + } + + fn main() { + let array: [u1; 2] = [0, 1]; + hello(array); + } + "#; + assert_eq!(get_program_errors(src).len(), 0); + } + + // Regression for #4545 + #[test] + fn type_aliases_in_main() { + let src = r#" + type Outer = [u8; N]; + fn main(_arg: Outer<1>) {} + "#; + assert_eq!(get_program_errors(src).len(), 0); + } } diff --git a/test_programs/compile_failure/self_referential_struct/src/main.nr b/test_programs/compile_failure/self_referential_struct/src/main.nr index 4c9b0095c71..d70b1a10ded 100644 --- a/test_programs/compile_failure/self_referential_struct/src/main.nr +++ b/test_programs/compile_failure/self_referential_struct/src/main.nr @@ -1,11 +1,11 @@ -struct SelfReferential -{ - prop : Option +struct Option2 { + _is_some: bool, + _value: T, } -#[test] -unconstrained -fn test_self_referential() +struct SelfReferential { - let self_ref = SelfReferential { prop : Option::none() }; + prop : Option2 } + +fn main(x: SelfReferential) { assert(x._is_some); } From 9a8ac121ce3ca6f31cc9ea37c743351d698b91be Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Mon, 22 Apr 2024 15:50:01 -0400 Subject: [PATCH 03/11] cargo fmt/clippt --- compiler/noirc_frontend/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 53a6700362f..1e22a2fbb7d 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -1281,5 +1281,4 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { "#; assert_eq!(get_program_errors(src).len(), 0); } - } From 380fb0ab4cd15ee966e8604a840f0991b018219c Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Mon, 22 Apr 2024 15:54:31 -0400 Subject: [PATCH 04/11] remove duplicated test, revert debugging changes to node interner, revert spurious change to Cargo.toml --- Cargo.toml | 1 + compiler/noirc_frontend/src/hir/type_check/mod.rs | 12 ------------ compiler/noirc_frontend/src/node_interner.rs | 4 ++-- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f333a43a1a6..cdbb40f630a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,7 @@ noir_lsp = { path = "tooling/lsp" } noir_debugger = { path = "tooling/debugger" } noirc_abi = { path = "tooling/noirc_abi" } bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } +acvm_cli = { path = "tooling/acvm_cli" } # LSP async-lsp = { version = "0.1.0", default-features = false } diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 449b256b3d9..f238c98d04b 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -638,18 +638,6 @@ pub mod test { type_check_src_code_errors_expected(src, vec![String::from("fold")], 1); } - #[test] - fn fold_entry_point() { - let src = r#" - #[fold] - fn fold(x: &mut Field) -> Field { - *x - } - "#; - - type_check_src_code_errors_expected(src, vec![String::from("fold")], 1); - } - // This is the same Stub that is in the resolver, maybe we can pull this out into a test module and re-use? struct TestPathResolver(HashMap); diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index fd10fb8b2ce..5b375be8d56 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -88,7 +88,7 @@ pub struct NodeInterner { // Each struct definition is possibly shared across multiple type nodes. // It is also mutated through the RefCell during name resolution to append // methods from impls to the type. - pub(crate) structs: HashMap>, + structs: HashMap>, struct_attributes: HashMap, @@ -1579,7 +1579,7 @@ impl NodeInterner { self.dependency_graph.update_edge(dependent_index, dependency_index, ()); } - pub(crate) fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { + fn get_or_insert_dependency(&mut self, id: DependencyId) -> PetGraphIndex { if let Some(index) = self.dependency_graph_indices.get(&id) { return *index; } From e5e5f3ad0c62a5a89d16fbe43008aa322c6d8c21 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Wed, 24 Apr 2024 15:23:56 -0400 Subject: [PATCH 05/11] use StructId instead of Ident to identify structs --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 12c197df647..85d7cceed94 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -97,7 +97,7 @@ pub struct Resolver<'a> { current_item: Option, /// In-resolution names - resolving_names: BTreeSet, + resolving_names: BTreeSet, /// True if the current module is a contract. /// This is usually determined by self.path_resolver.module_id(), but it can @@ -620,7 +620,7 @@ impl<'a> Resolver<'a> { match self.lookup_struct_or_error(path) { Some(struct_type) => { - if self.resolving_names.contains(&struct_type.borrow().name) { + if self.resolving_names.contains(&struct_type.borrow().id) { self.push_err(ResolverError::SelfReferentialStruct { span: struct_type.borrow().name.span(), }); @@ -899,9 +899,9 @@ impl<'a> Resolver<'a> { self.current_item = Some(DependencyId::Struct(struct_id)); - self.resolving_names.insert(unresolved.name.clone()); + self.resolving_names.insert(struct_id); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); - self.resolving_names.remove(&unresolved.name); + self.resolving_names.remove(&struct_id); (generics, fields, self.errors) } From 513eaecae3f2d9738b83351e9884b6eb6bef350e Mon Sep 17 00:00:00 2001 From: jfecher Date: Thu, 25 Apr 2024 10:26:51 -0500 Subject: [PATCH 06/11] Update compiler/noirc_frontend/src/hir/resolution/resolver.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 85d7cceed94..62ddff3d8ca 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -97,7 +97,7 @@ pub struct Resolver<'a> { current_item: Option, /// In-resolution names - resolving_names: BTreeSet, + resolving_ids: BTreeSet, /// True if the current module is a contract. /// This is usually determined by self.path_resolver.module_id(), but it can From e90ab088ae2182d84c6a7c7a382ce24ed03cfca4 Mon Sep 17 00:00:00 2001 From: jfecher Date: Thu, 25 Apr 2024 10:26:59 -0500 Subject: [PATCH 07/11] Update compiler/noirc_frontend/src/hir/resolution/resolver.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 62ddff3d8ca..bf28003a14c 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -162,7 +162,7 @@ impl<'a> Resolver<'a> { lambda_stack: Vec::new(), current_trait_impl: None, current_item: None, - resolving_names: BTreeSet::new(), + resolving_ids: BTreeSet::new(), file, in_contract, in_unconstrained_fn: false, From 2225c6638d6b1b5827ddaf78abf059d2fb8e1a03 Mon Sep 17 00:00:00 2001 From: jfecher Date: Thu, 25 Apr 2024 10:27:08 -0500 Subject: [PATCH 08/11] Update compiler/noirc_frontend/src/hir/resolution/resolver.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index bf28003a14c..a9b7ac67029 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -620,7 +620,7 @@ impl<'a> Resolver<'a> { match self.lookup_struct_or_error(path) { Some(struct_type) => { - if self.resolving_names.contains(&struct_type.borrow().id) { + if self.resolving_ids.contains(&struct_type.borrow().id) { self.push_err(ResolverError::SelfReferentialStruct { span: struct_type.borrow().name.span(), }); From b452a9906a741a7dc349375e09041281174b2236 Mon Sep 17 00:00:00 2001 From: jfecher Date: Thu, 25 Apr 2024 10:27:16 -0500 Subject: [PATCH 09/11] Update compiler/noirc_frontend/src/hir/resolution/resolver.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index a9b7ac67029..3050d906336 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -899,7 +899,7 @@ impl<'a> Resolver<'a> { self.current_item = Some(DependencyId::Struct(struct_id)); - self.resolving_names.insert(struct_id); + self.resolving_ids.insert(struct_id); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); self.resolving_names.remove(&struct_id); From 358937752da9f7c097e045524a3f2a5df13c31df Mon Sep 17 00:00:00 2001 From: jfecher Date: Thu, 25 Apr 2024 10:27:26 -0500 Subject: [PATCH 10/11] Update compiler/noirc_frontend/src/hir/resolution/resolver.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- compiler/noirc_frontend/src/hir/resolution/resolver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 3050d906336..289fdbccffc 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -901,7 +901,7 @@ impl<'a> Resolver<'a> { self.resolving_ids.insert(struct_id); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); - self.resolving_names.remove(&struct_id); + self.resolving_ids.remove(&struct_id); (generics, fields, self.errors) } From 6a2d10c7edaf9b1406933796e9de8fd241f7dc0b Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Fri, 26 Apr 2024 14:34:02 -0400 Subject: [PATCH 11/11] add explanation of BtreeSet in defintion of resolving_ids --- .../noirc_frontend/src/hir/resolution/resolver.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index c67dea03f4a..e3b1251955c 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -97,6 +97,18 @@ pub struct Resolver<'a> { current_item: Option, /// In-resolution names + /// + /// This needs to be a set because we can have multiple in-resolution + /// names when resolving structs that are declared in reverse order of their + /// dependencies, such as in the following case: + /// + /// ``` + /// struct Wrapper { + /// value: Wrapped + /// } + /// struct Wrapped { + /// } + /// ``` resolving_ids: BTreeSet, /// True if the current module is a contract.