From b93257ecc22cf6b65668ee417ad8fcef913e85d5 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Mon, 22 Apr 2024 17:23:17 -0400 Subject: [PATCH 1/7] add dbg statements, add wip unit test, add wip test program --- .../noirc_frontend/src/hir/type_check/expr.rs | 1 + compiler/noirc_frontend/src/node_interner.rs | 1 + compiler/noirc_frontend/src/tests.rs | 20 +++++++++ .../impl_from_where_impl/Nargo.toml | 7 +++ .../impl_from_where_impl/src/main.nr | 45 +++++++++++++++++++ 5 files changed, 74 insertions(+) create mode 100644 test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml create mode 100644 test_programs/compile_success_empty/impl_from_where_impl/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 62330732be4..f6f18aac411 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -1263,6 +1263,7 @@ impl<'interner> TypeChecker<'interner> { object_type: &Type, span: Span, ) { + dbg!("typecheck_operator_method:", expr_id, trait_method_id, object_type, span, &self.interner.traits); let the_trait = self.interner.get_trait(trait_method_id.trait_id); let method = &the_trait.methods[trait_method_id.method_index]; diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index b0e68be4868..85b6aa272e8 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -948,6 +948,7 @@ impl NodeInterner { } pub fn get_trait(&self, id: TraitId) -> &Trait { + dbg!("get_trait: {:?}", id); &self.traits[&id] } diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 31bf2245b1f..5bcf050bf01 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -91,6 +91,26 @@ mod test { get_program(src).2 } + // TODO: relocate to end of trait tests + #[test] + fn test_impl_self_within_def() { + let src = " + // trait Ord { + // fn cmp(self, other: Self) -> Ordering; + // + // // fn max2(self, other: Self) -> Self; + // } + + fn max_of_both(lhs: T, rhs: T) -> bool where T: Ord { + if lhs > rhs { lhs } else { rhs } + }"; + + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + + #[test] fn check_trait_implemented_for_all_t() { let src = " diff --git a/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml b/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml new file mode 100644 index 00000000000..5894e457dd8 --- /dev/null +++ b/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "impl_from_where_impl" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] diff --git a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr new file mode 100644 index 00000000000..a4157089470 --- /dev/null +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -0,0 +1,45 @@ +// trait Ord { +// fn cmp(self, other: Self) -> Ordering; +// +// fn max(self, other: Self) -> Self { +// max(self, other) +// } +// } + +use dep::std::cmp::Ordering; + +trait Ord2 { + fn cmp2(self, other: Self) -> Ordering; + + fn max2(self, other: Self) -> Self; +} + + +fn max2(lhs: T, rhs: T) -> T where T: Ord2 { + if lhs.cmp2(rhs) == Ordering::greater() { lhs } else { rhs } +} + + +struct Foo { + value: T +} + +impl Ord2 for Foo where T: Ord2 { + fn cmp2(self, other: Self) -> Ordering { + Ordering::greater() + } + + fn max2(self, other: Self) -> Self { + if self.cmp2(other) == Ordering::greater() { self } else { other } + } +} + + + +fn max(lhs: T, rhs: T) -> T where T: Ord { + if lhs > rhs { lhs } else { rhs } +} + +fn main(x: Field, y: pub Field) { + assert(x != y); +} From 80b3176e919789ef29fe9d6a4a899dfa63b080ba Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Tue, 23 Apr 2024 16:20:13 -0400 Subject: [PATCH 2/7] very wip: appear to have fixed the issue, lots of debug statements, copy where_clause field from current impl to default impl's function where_clause field --- .../src/hir/def_collector/dc_crate.rs | 8 +- .../src/hir/resolution/traits.rs | 29 +- .../noirc_frontend/src/hir/type_check/expr.rs | 2 + .../noirc_frontend/src/hir/type_check/mod.rs | 17 + compiler/noirc_frontend/src/node_interner.rs | 40 +- compiler/noirc_frontend/src/tests.rs | 2406 +++++++++-------- .../impl_from_where_impl/src/main.nr | 160 +- 7 files changed, 1438 insertions(+), 1224 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 4c6b5ab5885..3c78f2f00a9 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -31,7 +31,8 @@ use std::collections::{BTreeMap, HashMap}; use std::vec; /// Stores all of the unresolved functions in a particular file/mod -#[derive(Clone)] +// TODO: remove debug +#[derive(Clone, Debug)] pub struct UnresolvedFunctions { pub file_id: FileId, pub functions: Vec<(LocalModuleId, FuncId, NoirFunction)>, @@ -79,7 +80,8 @@ pub struct UnresolvedStruct { pub struct_def: NoirStruct, } -#[derive(Clone)] +// TODO: remove debug +#[derive(Clone, Debug)] pub struct UnresolvedTrait { pub file_id: FileId, pub module_id: LocalModuleId, @@ -89,6 +91,8 @@ pub struct UnresolvedTrait { pub fns_with_default_impl: UnresolvedFunctions, } +// TODO: remove debug +#[derive(Debug)] pub struct UnresolvedTraitImpl { pub file_id: FileId, pub module_id: LocalModuleId, diff --git a/compiler/noirc_frontend/src/hir/resolution/traits.rs b/compiler/noirc_frontend/src/hir/resolution/traits.rs index ccae8c6dd03..19c0c4d92e3 100644 --- a/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -124,6 +124,8 @@ fn resolve_trait_methods( let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file); resolver.add_generics(generics); + + // TODO: THIS SEEMS TO BE WHERE IT COULD BE PICKED UP resolver.add_existing_generics(&unresolved_trait.trait_def.generics, trait_generics); resolver.add_existing_generic("Self", name_span, self_typevar); resolver.set_self_type(Some(self_type.clone())); @@ -137,6 +139,17 @@ fn resolve_trait_methods( where_clause, func_id, ); + + // // TODO: remove before PR + // dbg!("resolve_trait_methods!!!!!!!"); + // dbg!("resolve_trait_methods!!!!!!!"); + // dbg!("resolve_trait_methods!!!!!!!"); + // dbg!("resolve_trait_methods!!!!!!!"); + // dbg!("resolve_trait_methods!!!!!!!"); + // dbg!("resolve_trait_methods!!!!!!!"); + // dbg!(&func_meta.trait_constraints); + // // dbg!("resolve_trait_methods!!!!!!!", &name, &where_clause, &unresolved_trait, &unresolved_trait, &unresolved_trait.trait_def.generics, &trait_generics); + resolver.interner.push_fn_meta(func_meta, func_id); let arguments = vecmap(parameters, |param| resolver.resolve_type(param.1.clone())); @@ -182,6 +195,10 @@ fn collect_trait_impl_methods( trait_id: TraitId, trait_impl: &mut UnresolvedTraitImpl, ) -> Vec<(CompilationError, FileId)> { + // TODO: remove before PR + dbg!("collect_trait_impl_methods"); + // dbg!("collect_trait_impl_methods", &trait_impl); + // In this Vec methods[i] corresponds to trait.methods[i]. If the impl has no implementation // for a particular method, the default implementation will be added at that slot. let mut ordered_methods = Vec::new(); @@ -207,6 +224,16 @@ fn collect_trait_impl_methods( if overrides.is_empty() { if let Some(default_impl) = &method.default_impl { + dbg!("default impl", &default_impl, &method, &trait_id); + + let mut default_impl_clone = default_impl.clone(); + // copy where clause from unresolved trait + default_impl_clone.def.where_clause = trait_impl.where_clause.clone(); + + // let mut default_impl_def = default_impl.def.clone(); + // panic!("default impl triggered!"); + dbg!("default impl clone.def", &default_impl_clone.def); + let func_id = interner.push_empty_fn(); let module = ModuleId { local_id: trait_impl.module_id, krate: crate_id }; let location = Location::new(default_impl.def.span, trait_impl.file_id); @@ -215,7 +242,7 @@ fn collect_trait_impl_methods( ordered_methods.push(( method.default_impl_module_id, func_id, - *default_impl.clone(), + *default_impl_clone, )); } else { let error = DefCollectorErrorKind::TraitMissingMethod { diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index f6f18aac411..7d90fa5c5c0 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -439,6 +439,8 @@ impl<'interner> TypeChecker<'interner> { .collect::>>(); if let Some(constraints) = constraints { + dbg!("verify_type_constraint", object_type, trait_id, trait_generics, function_ident_id); + self.errors.push(TypeCheckError::NoMatchingImplFound { constraints, span }); } } diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 44dab6dee3d..6c8c29768c1 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -47,6 +47,8 @@ pub struct TypeChecker<'interner> { /// Type checks a function and assigns the /// appropriate types to expressions in a side table pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec { + dbg!("type_check_func", &interner.function_modifiers[&func_id].name); + let meta = interner.function_meta(&func_id); let declared_return_type = meta.return_type().clone(); let can_ignore_ret = meta.can_ignore_return_type(); @@ -62,14 +64,29 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec, + + // TODO: remove pub before PR + pub(crate) function_modifiers: HashMap, // Contains the source module each function was defined in function_modules: HashMap, @@ -948,7 +950,6 @@ impl NodeInterner { } pub fn get_trait(&self, id: TraitId) -> &Trait { - dbg!("get_trait: {:?}", id); &self.traits[&id] } @@ -1193,6 +1194,9 @@ impl NodeInterner { type_bindings: &mut TypeBindings, recursion_limit: u32, ) -> Result> { + // TODO: remove before PR + // dbg!("lookup_trait_implementation_helper", object_type, trait_id, trait_generics, type_bindings.clone()); + let make_constraint = || TraitConstraint::new(object_type.clone(), trait_id, trait_generics.to_vec()); @@ -1203,6 +1207,9 @@ impl NodeInterner { let object_type = object_type.substitute(type_bindings); + // TODO: remove before PR + // dbg!("lookup_trait_implementation_helper2", object_type.clone()); + // If the object type isn't known, just return an error saying type annotations are needed. if object_type.is_bindable() { return Err(Vec::new()); @@ -1211,6 +1218,11 @@ impl NodeInterner { let impls = self.trait_implementation_map.get(&trait_id).ok_or_else(|| vec![make_constraint()])?; + // TODO: remove before PR + // dbg!("lookup_trait_implementation_helper3", impls); + dbg!("lookup_trait_implementation_helper: map", &self.trait_implementation_map); + // dbg!("lookup_trait_implementation_helper: selected", &self.selected_trait_implementations); + let mut matching_impls = Vec::new(); for (existing_object_type2, impl_kind) in impls { @@ -1322,13 +1334,27 @@ impl NodeInterner { trait_id: TraitId, trait_generics: Vec, ) -> bool { + // TODO: remove before PR + dbg!("add_assumed_trait_implementation called!", &object_type, trait_id, &trait_generics); + // Make sure there are no overlapping impls if self.try_lookup_trait_implementation(&object_type, trait_id, &trait_generics).is_ok() { + dbg!("add_assumed_trait_implementation skipped!!!"); return false; } + // let mut tt: HashMap> = HashMap::new(); + // let ff = tt.entry(0).or_default(); + // ff.push(1); + // assert_eq!(tt, HashMap::new()); + + dbg!("add_assumed_trait_implementation called! (2)"); + + dbg!(&self.trait_implementation_map); let entries = self.trait_implementation_map.entry(trait_id).or_default(); entries.push((object_type.clone(), TraitImplKind::Assumed { object_type, trait_generics })); + + dbg!(&self.trait_implementation_map); true } @@ -1354,6 +1380,16 @@ impl NodeInterner { let instantiated_object_type = object_type.substitute(&substitutions); + // TODO: remove before PR + if let Ok((TraitImplKind::Assumed { .. }, _)) = self.try_lookup_trait_implementation( + &instantiated_object_type, + trait_id, + &trait_generics, + ) { + panic!("found assumed trait!"); + } + // TODO: end remove before PR + // Ignoring overlapping `TraitImplKind::Assumed` impls here is perfectly fine. // It should never happen since impls are defined at global scope, but even // if they were, we should never prevent defining a new impl because a 'where' diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 5bcf050bf01..b7a539ab25c 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -95,1211 +95,1237 @@ mod test { #[test] fn test_impl_self_within_def() { let src = " - // trait Ord { - // fn cmp(self, other: Self) -> Ordering; + + // trait Bar { + // fn ok(self) -> Self; + // } // - // // fn max2(self, other: Self) -> Self; + // trait Qux { + // fn id(self) -> Self { + // self + // } + // } + // + // // impl Bar for (T, T) where T: Bar { + // impl Bar for (T, T) where T: Bar { + // fn ok(self) -> Self { + // // self + // (self.0.ok(), self.1) + // } // } - fn max_of_both(lhs: T, rhs: T) -> bool where T: Ord { - if lhs > rhs { lhs } else { rhs } - }"; - - let errors = get_program_errors(src); - errors.iter().for_each(|err| println!("{:?}", err)); - assert!(errors.is_empty()); - } - + trait Bar { + fn ok(self) -> Self; - #[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()) + fn ref_ok(self) -> Self { + self.ok() } } - - 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() } + + impl Bar for (T, T) where T: Bar { + fn ok(self) -> Self { + self } - } - - 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"), - HirStatement::Comptime(_) => panic!("Unexpected comptime"), - }; - 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); + panic!("hi!"); } - #[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"), +// HirStatement::Comptime(_) => panic!("Unexpected comptime"), +// }; +// 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_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); +// } - #[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_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr index a4157089470..a1cde332af5 100644 --- a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -1,45 +1,147 @@ -// trait Ord { -// fn cmp(self, other: Self) -> Ordering; +// use dep::std::cmp::Ordering; + +trait Bar { + fn ok(self) -> Self; + + fn ref_ok(self) -> Self { + self.ok() + } +} + +impl Bar for (T, T) where T: Bar { + fn ok(self) -> Self { + self + } +} + +// trait Bar { +// fn ok(self) -> Self; +// } // -// fn max(self, other: Self) -> Self { -// max(self, other) +// trait Qux { +// fn id(self) -> Self { +// self +// } +// } +// +// // impl Bar for (T, T) where T: Bar { +// impl Bar for (T, T) where T: Bar { +// fn ok(self) -> Self { +// // self +// (self.0.ok(), self.1) // } // } -use dep::std::cmp::Ordering; +// fn ref_ok(self) -> Self { +// self.ok() +// } -trait Ord2 { - fn cmp2(self, other: Self) -> Ordering; +// struct Foo { +// value: U +// } +// +// impl Bar for Foo where T: Bar { +// fn ok(self) -> Self { +// self +// } +// +// } - fn max2(self, other: Self) -> Self; -} +// impl Bar for Foo where T: Bar { +// fn ok(self) -> Self { +// self +// } +// } -fn max2(lhs: T, rhs: T) -> T where T: Ord2 { - if lhs.cmp2(rhs) == Ordering::greater() { lhs } else { rhs } -} +// This works: +// +// trait Bar { +// fn ok(self) -> Self; +// +// fn ref_ok(self) -> Self; +// } +// +// impl Bar for Foo where T: Bar { +// fn ok(self) -> Self { +// self +// } +// +// fn ref_ok(self) -> Self { +// self.ok() +// } +// } -struct Foo { - value: T -} -impl Ord2 for Foo where T: Ord2 { - fn cmp2(self, other: Self) -> Ordering { - Ordering::greater() - } +// trait Ord2 { +// fn cmp2(self, other: Self) -> Ordering; +// +// fn max2(self, rhs: Self) -> Self { +// if self.cmp2(rhs) == Ordering::greater() { self } else { rhs } +// } +// } +// +// impl Ord2 for Foo where T: Ord2 { +// fn cmp2(_self: Self, _other: Self) -> Ordering { +// Ordering::greater() +// } +// } - fn max2(self, other: Self) -> Self { - if self.cmp2(other) == Ordering::greater() { self } else { other } - } +fn main() { + // let foo: Foo = Foo { value: 7 }; + // let _ = foo.cmp2(foo); } +// impl Ord2 for u32 { +// fn cmp2(_self: Self, _other: Self) -> Ordering { +// Ordering::equal() +// } +// } +// // trait Ord { +// // fn cmp(self, other: Self) -> Ordering; +// // +// // fn max(self, other: Self) -> Self { +// // max(self, other) +// // } +// // } +// +// use dep::std::cmp::Ordering; +// +// trait Ord2 { +// fn cmp2(self, other: Self) -> Ordering; +// +// fn max2(self, other: Self) -> Self; +// } +// +// +// fn max2(lhs: T, rhs: T) -> T where T: Ord2 { +// if lhs.cmp2(rhs) == Ordering::greater() { lhs } else { rhs } +// } +// +// +// struct Foo { +// value: T +// } +// +// impl Ord2 for Foo where T: Ord2 { +// fn cmp2(self, other: Self) -> Ordering { +// Ordering::greater() +// } +// +// fn max2(self, other: Self) -> Self { +// if self.cmp2(other) == Ordering::greater() { self } else { other } +// } +// } +// +// +// +// fn max(lhs: T, rhs: T) -> T where T: Ord { +// if lhs > rhs { lhs } else { rhs } +// } +// +// fn main(x: Field, y: pub Field) { +// assert(x != y); +// } -fn max(lhs: T, rhs: T) -> T where T: Ord { - if lhs > rhs { lhs } else { rhs } -} - -fn main(x: Field, y: pub Field) { - assert(x != y); -} From af5a8c8800d07baa4b278712e4e444b4abf89677 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Tue, 23 Apr 2024 16:26:59 -0400 Subject: [PATCH 3/7] cleanup dbg and Debug derive's, cleanup comments, restore unit tests, cargo fmt/clippy --- .../src/hir/def_collector/dc_crate.rs | 8 +- .../src/hir/resolution/traits.rs | 30 +- .../noirc_frontend/src/hir/type_check/expr.rs | 3 - .../noirc_frontend/src/hir/type_check/mod.rs | 17 - compiler/noirc_frontend/src/node_interner.rs | 39 +- compiler/noirc_frontend/src/tests.rs | 2398 ++++++++--------- .../impl_from_where_impl/src/main.nr | 134 - 7 files changed, 1192 insertions(+), 1437 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 3c78f2f00a9..4c6b5ab5885 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -31,8 +31,7 @@ use std::collections::{BTreeMap, HashMap}; use std::vec; /// Stores all of the unresolved functions in a particular file/mod -// TODO: remove debug -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct UnresolvedFunctions { pub file_id: FileId, pub functions: Vec<(LocalModuleId, FuncId, NoirFunction)>, @@ -80,8 +79,7 @@ pub struct UnresolvedStruct { pub struct_def: NoirStruct, } -// TODO: remove debug -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct UnresolvedTrait { pub file_id: FileId, pub module_id: LocalModuleId, @@ -91,8 +89,6 @@ pub struct UnresolvedTrait { pub fns_with_default_impl: UnresolvedFunctions, } -// TODO: remove debug -#[derive(Debug)] pub struct UnresolvedTraitImpl { pub file_id: FileId, pub module_id: LocalModuleId, diff --git a/compiler/noirc_frontend/src/hir/resolution/traits.rs b/compiler/noirc_frontend/src/hir/resolution/traits.rs index 19c0c4d92e3..c73b122d318 100644 --- a/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -125,7 +125,6 @@ fn resolve_trait_methods( let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file); resolver.add_generics(generics); - // TODO: THIS SEEMS TO BE WHERE IT COULD BE PICKED UP resolver.add_existing_generics(&unresolved_trait.trait_def.generics, trait_generics); resolver.add_existing_generic("Self", name_span, self_typevar); resolver.set_self_type(Some(self_type.clone())); @@ -139,17 +138,6 @@ fn resolve_trait_methods( where_clause, func_id, ); - - // // TODO: remove before PR - // dbg!("resolve_trait_methods!!!!!!!"); - // dbg!("resolve_trait_methods!!!!!!!"); - // dbg!("resolve_trait_methods!!!!!!!"); - // dbg!("resolve_trait_methods!!!!!!!"); - // dbg!("resolve_trait_methods!!!!!!!"); - // dbg!("resolve_trait_methods!!!!!!!"); - // dbg!(&func_meta.trait_constraints); - // // dbg!("resolve_trait_methods!!!!!!!", &name, &where_clause, &unresolved_trait, &unresolved_trait, &unresolved_trait.trait_def.generics, &trait_generics); - resolver.interner.push_fn_meta(func_meta, func_id); let arguments = vecmap(parameters, |param| resolver.resolve_type(param.1.clone())); @@ -195,10 +183,6 @@ fn collect_trait_impl_methods( trait_id: TraitId, trait_impl: &mut UnresolvedTraitImpl, ) -> Vec<(CompilationError, FileId)> { - // TODO: remove before PR - dbg!("collect_trait_impl_methods"); - // dbg!("collect_trait_impl_methods", &trait_impl); - // In this Vec methods[i] corresponds to trait.methods[i]. If the impl has no implementation // for a particular method, the default implementation will be added at that slot. let mut ordered_methods = Vec::new(); @@ -224,26 +208,16 @@ fn collect_trait_impl_methods( if overrides.is_empty() { if let Some(default_impl) = &method.default_impl { - dbg!("default impl", &default_impl, &method, &trait_id); - + // copy 'where' clause from unresolved trait impl let mut default_impl_clone = default_impl.clone(); - // copy where clause from unresolved trait default_impl_clone.def.where_clause = trait_impl.where_clause.clone(); - // let mut default_impl_def = default_impl.def.clone(); - // panic!("default impl triggered!"); - dbg!("default impl clone.def", &default_impl_clone.def); - let func_id = interner.push_empty_fn(); let module = ModuleId { local_id: trait_impl.module_id, krate: crate_id }; let location = Location::new(default_impl.def.span, trait_impl.file_id); interner.push_function(func_id, &default_impl.def, module, location); func_ids_in_trait.insert(func_id); - ordered_methods.push(( - method.default_impl_module_id, - func_id, - *default_impl_clone, - )); + ordered_methods.push((method.default_impl_module_id, func_id, *default_impl_clone)); } else { let error = DefCollectorErrorKind::TraitMissingMethod { trait_name: interner.get_trait(trait_id).name.clone(), diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 7d90fa5c5c0..62330732be4 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -439,8 +439,6 @@ impl<'interner> TypeChecker<'interner> { .collect::>>(); if let Some(constraints) = constraints { - dbg!("verify_type_constraint", object_type, trait_id, trait_generics, function_ident_id); - self.errors.push(TypeCheckError::NoMatchingImplFound { constraints, span }); } } @@ -1265,7 +1263,6 @@ impl<'interner> TypeChecker<'interner> { object_type: &Type, span: Span, ) { - dbg!("typecheck_operator_method:", expr_id, trait_method_id, object_type, span, &self.interner.traits); let the_trait = self.interner.get_trait(trait_method_id.trait_id); let method = &the_trait.methods[trait_method_id.method_index]; diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 6c8c29768c1..44dab6dee3d 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -47,8 +47,6 @@ pub struct TypeChecker<'interner> { /// Type checks a function and assigns the /// appropriate types to expressions in a side table pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec { - dbg!("type_check_func", &interner.function_modifiers[&func_id].name); - let meta = interner.function_meta(&func_id); let declared_return_type = meta.return_type().clone(); let can_ignore_ret = meta.can_ignore_return_type(); @@ -64,29 +62,14 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec, + function_modifiers: HashMap, // Contains the source module each function was defined in function_modules: HashMap, @@ -1194,9 +1192,6 @@ impl NodeInterner { type_bindings: &mut TypeBindings, recursion_limit: u32, ) -> Result> { - // TODO: remove before PR - // dbg!("lookup_trait_implementation_helper", object_type, trait_id, trait_generics, type_bindings.clone()); - let make_constraint = || TraitConstraint::new(object_type.clone(), trait_id, trait_generics.to_vec()); @@ -1207,9 +1202,6 @@ impl NodeInterner { let object_type = object_type.substitute(type_bindings); - // TODO: remove before PR - // dbg!("lookup_trait_implementation_helper2", object_type.clone()); - // If the object type isn't known, just return an error saying type annotations are needed. if object_type.is_bindable() { return Err(Vec::new()); @@ -1218,11 +1210,6 @@ impl NodeInterner { let impls = self.trait_implementation_map.get(&trait_id).ok_or_else(|| vec![make_constraint()])?; - // TODO: remove before PR - // dbg!("lookup_trait_implementation_helper3", impls); - dbg!("lookup_trait_implementation_helper: map", &self.trait_implementation_map); - // dbg!("lookup_trait_implementation_helper: selected", &self.selected_trait_implementations); - let mut matching_impls = Vec::new(); for (existing_object_type2, impl_kind) in impls { @@ -1334,27 +1321,13 @@ impl NodeInterner { trait_id: TraitId, trait_generics: Vec, ) -> bool { - // TODO: remove before PR - dbg!("add_assumed_trait_implementation called!", &object_type, trait_id, &trait_generics); - // Make sure there are no overlapping impls if self.try_lookup_trait_implementation(&object_type, trait_id, &trait_generics).is_ok() { - dbg!("add_assumed_trait_implementation skipped!!!"); return false; } - // let mut tt: HashMap> = HashMap::new(); - // let ff = tt.entry(0).or_default(); - // ff.push(1); - // assert_eq!(tt, HashMap::new()); - - dbg!("add_assumed_trait_implementation called! (2)"); - - dbg!(&self.trait_implementation_map); let entries = self.trait_implementation_map.entry(trait_id).or_default(); entries.push((object_type.clone(), TraitImplKind::Assumed { object_type, trait_generics })); - - dbg!(&self.trait_implementation_map); true } @@ -1380,16 +1353,6 @@ impl NodeInterner { let instantiated_object_type = object_type.substitute(&substitutions); - // TODO: remove before PR - if let Ok((TraitImplKind::Assumed { .. }, _)) = self.try_lookup_trait_implementation( - &instantiated_object_type, - trait_id, - &trait_generics, - ) { - panic!("found assumed trait!"); - } - // TODO: end remove before PR - // Ignoring overlapping `TraitImplKind::Assumed` impls here is perfectly fine. // It should never happen since impls are defined at global scope, but even // if they were, we should never prevent defining a new impl because a 'where' diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index b7a539ab25c..dc5c14aefa5 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -91,29 +91,664 @@ mod test { get_program(src).2 } - // TODO: relocate to end of trait tests #[test] - fn test_impl_self_within_def() { + 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); + } + }; + } + } - // trait Bar { - // fn ok(self) -> Self; - // } - // - // trait Qux { - // fn id(self) -> Self { - // self - // } - // } - // - // // impl Bar for (T, T) where T: Bar { - // impl Bar for (T, T) where T: Bar { - // fn ok(self) -> Self { - // // self - // (self.0.ok(), self.1) - // } - // } + #[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); + } + }; + } + } + #[test] + fn test_impl_self_within_default_def() { + let src = " trait Bar { fn ok(self) -> Self; @@ -131,1201 +766,542 @@ mod test { let errors = get_program_errors(src); errors.iter().for_each(|err| println!("{:?}", err)); assert!(errors.is_empty()); + } + + 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"), + HirStatement::Comptime(_) => panic!("Unexpected comptime"), + }; + 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!(), + }; + } + } - panic!("hi!"); + 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 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"), -// HirStatement::Comptime(_) => panic!("Unexpected comptime"), -// }; -// 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_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); -// } + #[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_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr index a1cde332af5..8b6094c3e51 100644 --- a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -1,5 +1,3 @@ -// use dep::std::cmp::Ordering; - trait Bar { fn ok(self) -> Self; @@ -13,135 +11,3 @@ impl Bar for (T, T) where T: Bar { self } } - -// trait Bar { -// fn ok(self) -> Self; -// } -// -// trait Qux { -// fn id(self) -> Self { -// self -// } -// } -// -// // impl Bar for (T, T) where T: Bar { -// impl Bar for (T, T) where T: Bar { -// fn ok(self) -> Self { -// // self -// (self.0.ok(), self.1) -// } -// } - -// fn ref_ok(self) -> Self { -// self.ok() -// } - -// struct Foo { -// value: U -// } -// -// impl Bar for Foo where T: Bar { -// fn ok(self) -> Self { -// self -// } -// -// } - -// impl Bar for Foo where T: Bar { -// fn ok(self) -> Self { -// self -// } -// } - - -// This works: -// -// trait Bar { -// fn ok(self) -> Self; -// -// fn ref_ok(self) -> Self; -// } -// -// impl Bar for Foo where T: Bar { -// fn ok(self) -> Self { -// self -// } -// -// fn ref_ok(self) -> Self { -// self.ok() -// } -// } - - - -// trait Ord2 { -// fn cmp2(self, other: Self) -> Ordering; -// -// fn max2(self, rhs: Self) -> Self { -// if self.cmp2(rhs) == Ordering::greater() { self } else { rhs } -// } -// } -// -// impl Ord2 for Foo where T: Ord2 { -// fn cmp2(_self: Self, _other: Self) -> Ordering { -// Ordering::greater() -// } -// } - -fn main() { - // let foo: Foo = Foo { value: 7 }; - // let _ = foo.cmp2(foo); -} - -// impl Ord2 for u32 { -// fn cmp2(_self: Self, _other: Self) -> Ordering { -// Ordering::equal() -// } -// } - -// // trait Ord { -// // fn cmp(self, other: Self) -> Ordering; -// // -// // fn max(self, other: Self) -> Self { -// // max(self, other) -// // } -// // } -// -// use dep::std::cmp::Ordering; -// -// trait Ord2 { -// fn cmp2(self, other: Self) -> Ordering; -// -// fn max2(self, other: Self) -> Self; -// } -// -// -// fn max2(lhs: T, rhs: T) -> T where T: Ord2 { -// if lhs.cmp2(rhs) == Ordering::greater() { lhs } else { rhs } -// } -// -// -// struct Foo { -// value: T -// } -// -// impl Ord2 for Foo where T: Ord2 { -// fn cmp2(self, other: Self) -> Ordering { -// Ordering::greater() -// } -// -// fn max2(self, other: Self) -> Self { -// if self.cmp2(other) == Ordering::greater() { self } else { other } -// } -// } -// -// -// -// fn max(lhs: T, rhs: T) -> T where T: Ord { -// if lhs > rhs { lhs } else { rhs } -// } -// -// fn main(x: Field, y: pub Field) { -// assert(x != y); -// } - From 591faa4aae1a83b752255880d5e7f32f00ffd4ca Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Tue, 23 Apr 2024 16:37:54 -0400 Subject: [PATCH 4/7] add back missing main() to test --- .../compile_success_empty/impl_from_where_impl/src/main.nr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr index 8b6094c3e51..8732229d646 100644 --- a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -11,3 +11,5 @@ impl Bar for (T, T) where T: Bar { self } } + +fn main() { } From e3024238231c31620ff17e1b220bdfcf168ce226 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Wed, 24 Apr 2024 15:40:29 -0400 Subject: [PATCH 5/7] fix 'nargo fmt' extra space in empty main() --- .../compile_success_empty/impl_from_where_impl/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr index 8732229d646..3cec46bdfcd 100644 --- a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -12,4 +12,4 @@ impl Bar for (T, T) where T: Bar { } } -fn main() { } +fn main() {} From 04b7bee5e1832bbbcaa4f857371f6c80f534f4e8 Mon Sep 17 00:00:00 2001 From: "Michael J. Klein" Date: Mon, 29 Apr 2024 14:19:13 -0400 Subject: [PATCH 6/7] fix mangled test from merging master --- compiler/noirc_frontend/src/tests.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index f0ee3b2147d..b2cc7eee9f8 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -761,7 +761,13 @@ mod test { fn ok(self) -> Self { self } + }"; + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + #[test] fn check_trait_as_type_as_fn_parameter() { let src = " trait Eq { From d1f96a1621db4ed1462ce95b39f7f3a2894ec451 Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 29 Apr 2024 14:06:12 -0500 Subject: [PATCH 7/7] Update compiler/noirc_frontend/src/hir/resolution/traits.rs --- compiler/noirc_frontend/src/hir/resolution/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/hir/resolution/traits.rs b/compiler/noirc_frontend/src/hir/resolution/traits.rs index c73b122d318..3d355fd4447 100644 --- a/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -210,7 +210,7 @@ fn collect_trait_impl_methods( if let Some(default_impl) = &method.default_impl { // copy 'where' clause from unresolved trait impl let mut default_impl_clone = default_impl.clone(); - default_impl_clone.def.where_clause = trait_impl.where_clause.clone(); + default_impl_clone.def.where_clause.extend(trait_impl.where_clause.clone()); let func_id = interner.push_empty_fn(); let module = ModuleId { local_id: trait_impl.module_id, krate: crate_id };