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 d3036f2ca4a..13cf6117172 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -93,6 +93,7 @@ pub struct DefCollector { pub(crate) collected_traits_impls: TraitImplMap, } +#[derive(Debug, Clone)] pub enum CompilationError { ParseError(ParserError), DefinitionError(DefCollectorErrorKind), diff --git a/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/compiler/noirc_frontend/src/hir/def_collector/errors.rs index 3c611baa379..a2d0cefdc2d 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/errors.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/errors.rs @@ -7,7 +7,7 @@ use thiserror::Error; use std::fmt; -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] pub enum DuplicateType { Function, Module, @@ -18,7 +18,7 @@ pub enum DuplicateType { TraitImplementation, } -#[derive(Error, Debug)] +#[derive(Error, Debug, Clone)] pub enum DefCollectorErrorKind { #[error("duplicate {typ} found in namespace")] Duplicate { typ: DuplicateType, first_def: Ident, second_def: Ident }, diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 4226454f903..1f7dc16d153 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -248,9 +248,7 @@ pub struct Contract { /// Given a FileId, fetch the File, from the FileManager and parse it's content pub fn parse_file(fm: &FileManager, file_id: FileId) -> (ParsedModule, Vec) { let file = fm.fetch_file(file_id); - let (program, errors) = parse_program(file.source()); - - (program, errors) + parse_program(file.source()) } impl std::ops::Index for CrateDefMap { diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index f2f3ae0c5a5..cc0b3ba7808 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -1551,526 +1551,3 @@ pub fn verify_mutable_reference(interner: &NodeInterner, rhs: ExprId) -> Result< _ => Ok(()), } } - -// XXX: These tests repeat a lot of code -// what we should do is have test cases which are passed to a test harness -// A test harness will allow for more expressive and readable tests -#[cfg(test)] -mod test { - - use core::panic; - use std::collections::BTreeMap; - - use fm::FileId; - use iter_extended::vecmap; - use noirc_errors::Location; - - use crate::hir::def_map::{ModuleData, ModuleId}; - use crate::hir::resolution::errors::ResolverError; - use crate::hir::resolution::import::PathResolutionError; - use crate::hir::resolution::resolver::StmtId; - - use super::{PathResolver, Resolver}; - use crate::graph::CrateId; - use crate::hir_def::expr::HirExpression; - use crate::hir_def::stmt::HirStatement; - use crate::node_interner::{FuncId, NodeInterner}; - use crate::ParsedModule; - use crate::{ - hir::def_map::{CrateDefMap, LocalModuleId, ModuleDefId}, - parse_program, Path, - }; - use noirc_errors::CustomDiagnostic; - - // func_namespace is used to emulate the fact that functions can be imported - // and functions can be forward declared - fn init_src_code_resolution( - src: &str, - ) -> (ParsedModule, NodeInterner, BTreeMap, FileId, TestPathResolver) - { - let (program, errors) = parse_program(src); - if errors.iter().any(|e| { - let diagnostic: CustomDiagnostic = e.clone().into(); - diagnostic.is_error() - }) { - panic!("Unexpected parse errors in test code: {:?}", errors); - } - - let interner: NodeInterner = NodeInterner::default(); - - let mut def_maps: BTreeMap = BTreeMap::new(); - let file = FileId::default(); - - let mut modules = arena::Arena::new(); - let location = Location::new(Default::default(), file); - modules.insert(ModuleData::new(None, location, false)); - - let path_resolver = TestPathResolver(BTreeMap::new()); - - def_maps.insert( - CrateId::dummy_id(), - CrateDefMap { - root: path_resolver.local_module_id(), - modules, - krate: CrateId::dummy_id(), - extern_prelude: BTreeMap::new(), - }, - ); - - (program, interner, def_maps, file, path_resolver) - } - - // func_namespace is used to emulate the fact that functions can be imported - // and functions can be forward declared - fn resolve_src_code(src: &str, func_namespace: Vec<&str>) -> Vec { - let (program, mut interner, def_maps, file, mut path_resolver) = - init_src_code_resolution(src); - - let func_ids = vecmap(&func_namespace, |name| { - interner.push_test_function_definition(name.to_string()) - }); - - for (name, id) in func_namespace.into_iter().zip(func_ids) { - path_resolver.insert_func(name.to_owned(), id); - } - - let mut errors = Vec::new(); - for func in program.functions { - let id = interner.push_test_function_definition(func.name().to_string()); - - let resolver = Resolver::new(&mut interner, &path_resolver, &def_maps, file); - let (_, _, err) = resolver.resolve_function(func, id); - errors.extend(err); - } - - errors - } - - fn get_program_captures(src: &str) -> Vec> { - let (program, mut interner, def_maps, file, mut path_resolver) = - init_src_code_resolution(src); - - let mut all_captures: Vec> = Vec::new(); - for func in program.functions { - let name = func.name().to_string(); - let id = interner.push_test_function_definition(name); - path_resolver.insert_func(func.name().to_owned(), id); - - let resolver = Resolver::new(&mut interner, &path_resolver, &def_maps, file); - let (hir_func, _, _) = resolver.resolve_function(func, id); - - // Iterate over function statements and apply filtering function - parse_statement_blocks( - hir_func.block(&interner).statements(), - &interner, - &mut all_captures, - ); - } - all_captures - } - - fn parse_statement_blocks( - stmts: &[StmtId], - interner: &NodeInterner, - result: &mut Vec>, - ) { - let mut expr: HirExpression; - - for stmt_id in stmts.iter() { - let hir_stmt = interner.statement(stmt_id); - match hir_stmt { - HirStatement::Expression(expr_id) => { - expr = interner.expression(&expr_id); - } - HirStatement::Let(let_stmt) => { - expr = interner.expression(&let_stmt.expression); - } - HirStatement::Assign(assign_stmt) => { - expr = interner.expression(&assign_stmt.expression); - } - HirStatement::Constrain(constr_stmt) => { - expr = interner.expression(&constr_stmt.0); - } - HirStatement::Semi(semi_expr) => { - expr = interner.expression(&semi_expr); - } - HirStatement::Error => panic!("Invalid HirStatement!"), - } - 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 { - parse_statement_blocks(block_expr.statements(), interner, result); - } - } - } - - #[test] - fn resolve_empty_function() { - let src = " - fn main() { - - } - "; - - let errors = resolve_src_code(src, vec!["main"]); - assert!(errors.is_empty()); - } - #[test] - fn resolve_basic_function() { - let src = r#" - fn main(x : Field) { - let y = x + x; - assert(y == x); - } - "#; - - let errors = resolve_src_code(src, vec!["main"]); - assert!(errors.is_empty()); - } - #[test] - fn resolve_unused_var() { - let src = r#" - fn main(x : Field) { - let y = x + x; - assert(x == x); - } - "#; - - let errors = resolve_src_code(src, vec!["main"]); - - // There should only be one error - assert!(errors.len() == 1, "Expected 1 error, got: {:?}", errors); - - // It should be regarding the unused variable - match &errors[0] { - 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 = resolve_src_code(src, vec!["main"]); - - // There should only be one error - assert!(errors.len() == 1); - - // It should be regarding the unresolved var `z` (Maybe change to undeclared and special case) - match &errors[0] { - 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 mut errors = resolve_src_code(src, vec!["main", "foo"]); - assert_eq!(errors.len(), 1); - let err = errors.pop().unwrap(); - - path_unresolved_error(err, "func"); - } - - #[test] - fn resolve_literal_expr() { - let src = r#" - fn main(x : Field) { - let y = 5; - assert(y == x); - } - "#; - - let errors = resolve_src_code(src, vec!["main"]); - assert!(errors.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 = resolve_src_code(src, vec!["main"]); - assert!(errors.len() == 3, "Expected 3 errors, got: {:?}", errors); - - // Errors are: - // `a` is undeclared - // `z` is unused - // `foo::bar` does not exist - for err in errors { - match &err { - ResolverError::UnusedVariable { ident } => { - assert_eq!(&ident.0.contents, "z"); - } - ResolverError::VariableNotDeclared { name, .. } => { - assert_eq!(name, "a"); - } - ResolverError::PathResolutionError(_) => path_unresolved_error(err, "bar"), - _ => unimplemented!(), - }; - } - } - - #[test] - fn resolve_prefix_expr() { - let src = r#" - fn main(x : Field) { - let _y = -x; - } - "#; - - let errors = resolve_src_code(src, vec!["main"]); - assert!(errors.is_empty()); - } - #[test] - fn resolve_for_expr() { - let src = r#" - fn main(x : Field) { - for i in 1..20 { - let _z = x + i; - }; - } - "#; - - let errors = resolve_src_code(src, vec!["main"]); - assert!(errors.is_empty()); - } - #[test] - fn resolve_call_expr() { - let src = r#" - fn main(x : Field) { - let _z = foo(x); - } - - fn foo(x : Field) -> Field { - x - } - "#; - - let errors = resolve_src_code(src, vec!["main", "foo"]); - assert!(errors.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 - } - "#; - let errors = resolve_src_code(src, vec!["main", "foo"]); - if !errors.is_empty() { - println!("Unexpected errors: {:?}", errors); - unreachable!("there should be no errors"); - } - } - - #[test] - fn resolve_basic_closure() { - let src = r#" - fn main(x : Field) -> pub Field { - let closure = |y| y + x; - closure(x) - } - "#; - - let errors = resolve_src_code(src, vec!["main", "foo"]); - if !errors.is_empty() { - panic!("Unexpected errors: {:?}", errors); - } - } - - #[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| x + x; - let a = closure_without_captures(1); - - let closure_capturing_a_param = |y| y + x; - let b = closure_capturing_a_param(2); - - let closure_capturing_a_local_var = |y| y + b; - let c = closure_capturing_a_local_var(3); - - let closure_with_transitive_captures = |y| { - let d = 5; - let nested_closure = |z| { - let doubly_nested_closure = |w| 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) - } - "#; - - let errors = resolve_src_code(src, vec!["main", "foo"]); - assert!(errors.is_empty()); - if !errors.is_empty() { - println!("Unexpected errors: {:?}", errors); - unreachable!("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"randomstring{new_val}{new_val}"); - } - fn println(x : T) -> T { - x - } - "#; - - let errors = resolve_src_code(src, vec!["main", "println"]); - assert!(errors.len() == 2, "Expected 2 errors, got: {:?}", errors); - - for err in errors { - match &err { - ResolverError::VariableNotDeclared { name, .. } => { - assert_eq!(name, "i"); - } - ResolverError::NumericConstantInFormatString { name, .. } => { - assert_eq!(name, "0"); - } - _ => unimplemented!(), - }; - } - } - - // possible TODO: Create a more sophisticated set of search functions over the HIR, so we can check - // that the correct variables are captured in each closure - - fn path_unresolved_error(err: ResolverError, expected_unresolved_path: &str) { - match err { - ResolverError::PathResolutionError(PathResolutionError::Unresolved(name)) => { - assert_eq!(name.to_string(), expected_unresolved_path); - } - _ => unimplemented!("expected an unresolved path"), - } - } - - struct TestPathResolver(BTreeMap); - - impl PathResolver for TestPathResolver { - fn resolve( - &self, - _def_maps: &BTreeMap, - path: Path, - ) -> Result { - // Not here that foo::bar and hello::foo::bar would fetch the same thing - let name = path.segments.last().unwrap(); - let mod_def = self.0.get(&name.0.contents).cloned(); - mod_def.ok_or_else(move || PathResolutionError::Unresolved(name.clone())) - } - - fn local_module_id(&self) -> LocalModuleId { - // This is not LocalModuleId::dummy since we need to use this to index into a Vec - // later and do not want to push u32::MAX number of elements before we do. - LocalModuleId(arena::Index::from_raw_parts(0, 0)) - } - - fn module_id(&self) -> ModuleId { - ModuleId { krate: CrateId::dummy_id(), local_id: self.local_module_id() } - } - } - - impl TestPathResolver { - fn insert_func(&mut self, name: String, func_id: FuncId) { - self.0.insert(name, func_id.into()); - } - } -} diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index e7d95d3dfc8..74057240de1 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -31,3 +31,6 @@ pub use ast::*; // Type API pub use hir_def::types::*; + +// Unit tests that involve all modules +pub mod tests; diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 07b60ae48e9..7225f53f283 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -1392,43 +1392,3 @@ fn undo_instantiation_bindings(bindings: TypeBindings) { *var.borrow_mut() = TypeBinding::Unbound(id); } } - -#[cfg(test)] -mod tests { - use std::collections::{BTreeMap, HashMap}; - - use crate::{ - graph::CrateId, - hir::{ - def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId}, - resolution::{import::PathResolutionError, path_resolver::PathResolver}, - }, - }; - - // TODO: refactor into a more general test utility? - // TestPathResolver struct and impls copied from hir / type_check / mod.rs - struct TestPathResolver(HashMap); - - impl PathResolver for TestPathResolver { - fn resolve( - &self, - _def_maps: &BTreeMap, - path: crate::Path, - ) -> Result { - // Not here that foo::bar and hello::foo::bar would fetch the same thing - let name = path.segments.last().unwrap(); - let mod_def = self.0.get(&name.0.contents).cloned(); - mod_def.ok_or_else(move || PathResolutionError::Unresolved(name.clone())) - } - - fn local_module_id(&self) -> LocalModuleId { - // This is not LocalModuleId::dummy since we need to use this to index into a Vec - // later and do not want to push u32::MAX number of elements before we do. - LocalModuleId(arena::Index::from_raw_parts(0, 0)) - } - - fn module_id(&self) -> ModuleId { - ModuleId { krate: CrateId::dummy_id(), local_id: self.local_module_id() } - } - } -} diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 01633c29178..31e9e9612af 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -555,6 +555,13 @@ impl NodeInterner { *func = hir_func; } + pub fn find_function(&self, function_name: &str) -> Option { + self.func_meta + .iter() + .find(|(func_id, _func_meta)| self.function_name(func_id) == function_name) + .map(|(func_id, _meta)| *func_id) + } + ///Interns a function's metadata. /// /// Note that the FuncId has been created already. diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index c9740f5c119..8d3c508ef49 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -92,6 +92,10 @@ impl ParserError { pub fn span(&self) -> Span { self.span } + + pub fn reason(&self) -> Option { + self.reason.clone() + } } impl std::fmt::Display for ParserError { diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs new file mode 100644 index 00000000000..620fa77a669 --- /dev/null +++ b/compiler/noirc_frontend/src/tests.rs @@ -0,0 +1,957 @@ +// XXX: These tests repeat a lot of code +// what we should do is have test cases which are passed to a test harness +// A test harness will allow for more expressive and readable tests +#[cfg(test)] +mod test { + + use core::panic; + use std::collections::BTreeMap; + + use fm::FileId; + use noirc_errors::Location; + + use crate::hir::def_collector::dc_crate::CompilationError; + use crate::hir::def_collector::errors::{DefCollectorErrorKind, DuplicateType}; + use crate::hir::def_map::ModuleData; + use crate::hir::resolution::errors::ResolverError; + use crate::hir::resolution::import::PathResolutionError; + use crate::hir::type_check::TypeCheckError; + use crate::hir::Context; + use crate::node_interner::{NodeInterner, StmtId}; + + use crate::graph::CrateGraph; + use crate::hir::def_collector::dc_crate::DefCollector; + use crate::hir_def::expr::HirExpression; + use crate::hir_def::stmt::HirStatement; + use crate::monomorphization::monomorphize; + use crate::parser::ParserErrorReason; + use crate::ParsedModule; + use crate::{ + hir::def_map::{CrateDefMap, LocalModuleId}, + parse_program, + }; + use arena::Arena; + use fm::FileManager; + + pub(crate) fn has_parser_error(errors: &Vec<(CompilationError, FileId)>) -> bool { + errors.iter().any(|(e, _f)| match e { + CompilationError::ParseError(_) => true, + _ => false, + }) + } + + pub(crate) fn remove_experimental_feature_warnings( + errors: Vec<(CompilationError, FileId)>, + ) -> Vec<(CompilationError, FileId)> { + errors + .iter() + .filter(|(e, _f)| match e.clone() { + CompilationError::ParseError(parser_error) => match parser_error.reason() { + Some(ParserErrorReason::ExperimentalFeature(_)) => false, + _ => true, + }, + _ => true, + }) + .cloned() + .collect() + } + + pub(crate) fn get_program( + src: &str, + ) -> (ParsedModule, Context, Vec<(CompilationError, FileId)>) { + let root = std::path::Path::new("/"); + let fm = FileManager::new(root); + let graph = CrateGraph::default(); + let mut context = Context::new(fm, graph); + let root_file_id = FileId::dummy(); + let root_crate_id = context.crate_graph.add_crate_root(root_file_id); + let (program, parser_errors) = parse_program(src); + let mut errors = remove_experimental_feature_warnings( + parser_errors.iter().cloned().map(|e| (e.into(), root_file_id)).collect(), + ); + if !has_parser_error(&errors) { + // Allocate a default Module for the root, giving it a ModuleId + let mut modules: Arena = Arena::default(); + let location = Location::new(Default::default(), root_file_id); + let root = modules.insert(ModuleData::new(None, location, false)); + let def_map = CrateDefMap { + root: LocalModuleId(root), + modules, + krate: root_crate_id, + extern_prelude: BTreeMap::new(), + }; + // Now we want to populate the CrateDefMap using the DefCollector + errors.extend(DefCollector::collect( + def_map, + &mut context, + program.clone(), + root_file_id, + )); + } + (program, context, errors) + } + + pub(crate) fn get_program_errors(src: &str) -> Vec<(CompilationError, FileId)> { + let (_program, _context, errors) = get_program(src); + errors + .iter() + .filter(|(e, _f)| match e.clone() { + CompilationError::ParseError(parser_error) => match parser_error.reason() { + Some(ParserErrorReason::ExperimentalFeature(_)) => false, + _ => true, + }, + _ => true, + }) + .cloned() + .collect() + } + + #[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::TraitImplementation); + assert_eq!(first_def, "default"); + assert_eq!(second_def, "default"); + } + _ => { + assert!(false, "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"); + } + _ => { + assert!(false, "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"); + } + _ => { + assert!(false, "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"); + } + _ => { + assert!(false, "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_ident, + }) => { + assert_eq!(trait_ident, "Default"); + } + _ => { + assert!(false, "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 doesnt_exist(x: Field, y: Field) -> Self { + Self { bar: x, array: [x,y] } + } + } + + fn main() { + }"; + let compilator_errors = get_program_errors(src); + assert!(!has_parser_error(&compilator_errors)); + assert!( + compilator_errors.len() == 1, + "Expected 1 compilation error, got: {:?}", + compilator_errors + ); + + for (err, _file_id) in compilator_errors { + match &err { + CompilationError::DefinitionError(DefCollectorErrorKind::MethodNotInTrait { + trait_name, + impl_method, + }) => { + assert_eq!(trait_name, "Default"); + assert_eq!(impl_method, "doesnt_exist"); + } + _ => { + assert!(false, "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"); + } + _ => { + assert!(false, "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"); + } + _ => { + assert!(false, "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() == 1, "Expected 1 error, got: {:?}", errors); + + for (err, _file_id) in errors { + match &err { + CompilationError::ResolveError(ResolverError::PathResolutionError( + path_solution_error, + )) => match path_solution_error { + PathResolutionError::Unresolved(ident) => { + assert_eq!(ident, "NotAType"); + } + _ => { + assert!(false, "No other errors are expected! Found = {:?}", err); + } + }, + _ => { + assert!(false, "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::DefinitionError( + DefCollectorErrorKind::MismatchTraitImplementationNumParameters { + actual_num_parameters, + expected_num_parameters, + trait_name, + method_name, + .. + }, + ) => { + assert_eq!(actual_num_parameters, &(1 as usize)); + assert_eq!(expected_num_parameters, &(2 as usize)); + assert_eq!(method_name, "default"); + assert_eq!(trait_name, "Default"); + } + _ => { + assert!( + false, + "No other errors are expected in this test case! 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.functions { + let func_id = interner.find_function(&func.name().to_string()).unwrap(); + let hir_func = interner.function(&func_id); + // Iterate over function statements and apply filtering function + parse_statement_blocks( + hir_func.block(&interner).statements(), + &interner, + &mut all_captures, + ); + } + all_captures + } + + fn parse_statement_blocks( + stmts: &[StmtId], + interner: &NodeInterner, + result: &mut Vec>, + ) { + let mut expr: HirExpression; + + for stmt_id in stmts.iter() { + let hir_stmt = interner.statement(stmt_id); + match hir_stmt { + HirStatement::Expression(expr_id) => { + expr = interner.expression(&expr_id); + } + HirStatement::Let(let_stmt) => { + expr = interner.expression(&let_stmt.expression); + } + HirStatement::Assign(assign_stmt) => { + expr = interner.expression(&assign_stmt.expression); + } + HirStatement::Constrain(constr_stmt) => { + expr = interner.expression(&constr_stmt.0); + } + HirStatement::Semi(semi_expr) => { + expr = interner.expression(&semi_expr); + } + HirStatement::Error => panic!("Invalid HirStatement!"), + } + 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 { + parse_statement_blocks(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::ResolveError(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::ResolveError(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::ResolveError(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::ResolveError(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 : Field) { + 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| x + x; + let a = closure_without_captures(1); + + let closure_capturing_a_param = |y| y + x; + let b = closure_capturing_a_param(2); + + let closure_capturing_a_local_var = |y| y + b; + let c = closure_capturing_a_local_var(3); + + let closure_with_transitive_captures = |y| { + let d = 5; + let nested_closure = |z| { + let doubly_nested_closure = |w| 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"randomstring{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::ResolveError(ResolverError::VariableNotDeclared { + name, .. + }) => { + assert_eq!(name, "i"); + } + CompilationError::ResolveError(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\"randomstring{new_val}{new_val}\")" + ); + } + _ => unimplemented!(), + }; + } + } + + fn check_rewrite(src: &str, expected: &str) { + let (_program, context, _errors) = get_program(src); + let main_func_id = context.def_interner.find_function("main").unwrap(); + let program = monomorphize(main_func_id, &context.def_interner); + 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); + } +} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/Nargo.toml similarity index 71% rename from tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/Nargo.toml rename to tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/Nargo.toml index 22d31e22e29..35f174bf546 100644 --- a/tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/Nargo.toml +++ b/tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "trait_not_in_scope" +name = "impl_trait_for_non_type" type = "bin" authors = [""] compiler_version = "0.9.0" diff --git a/tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/Prover.toml b/tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/Prover.toml similarity index 100% rename from tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/Prover.toml rename to tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/Prover.toml diff --git a/tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/src/main.nr b/tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/src/main.nr new file mode 100644 index 00000000000..8bd6aae8064 --- /dev/null +++ b/tooling/nargo_cli/tests/compile_failure/impl_trait_for_non_type/impl_trait_for_non_type/src/main.nr @@ -0,0 +1,15 @@ +use dep::std; + +trait Default { + fn default(x: Field, y: Field) -> Field; +} + + +impl Default for main { + fn default(x: Field, y: Field) -> Field { + x + y + } +} + +fn main(x: Field, y: Field) { +} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_missing_implementation/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/trait_missing_implementation/Nargo.toml deleted file mode 100644 index 75fb80c4bfa..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_missing_implementation/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "traits" -type = "bin" -authors = [""] -compiler_version = "0.1" - -[dependencies] diff --git a/tooling/nargo_cli/tests/compile_failure/trait_missing_implementation/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_missing_implementation/src/main.nr deleted file mode 100644 index 1f69d09924b..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_missing_implementation/src/main.nr +++ /dev/null @@ -1,22 +0,0 @@ -use dep::std; - -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(x: Field) { -} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/src/main.nr deleted file mode 100644 index 2f236e622f0..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_not_in_scope/src/main.nr +++ /dev/null @@ -1,16 +0,0 @@ -use dep::std; - -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(x: Field, y: Field) { -} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/Nargo.toml deleted file mode 100644 index c84f1f3c1c7..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "trait_wrong_method_name" -type = "bin" -authors = [""] -compiler_version = "0.9.0" - -[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/Prover.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/Prover.toml deleted file mode 100644 index 2c1854573a4..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 1 -y = 2 diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/src/main.nr deleted file mode 100644 index 470bed9b354..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_name/src/main.nr +++ /dev/null @@ -1,19 +0,0 @@ -use dep::std; - -trait Default { -} - -struct Foo { - bar: Field, - array: [Field; 2], -} - -// wrong trait name method should not compile -impl Default for Foo { - fn doesnt_exist(x: Field, y: Field) -> Self { - Self { bar: x, array: [x,y] } - } -} - -fn main(x: Field, y: Field) { -} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/Nargo.toml deleted file mode 100644 index 95e3e222ca3..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "trait_wrong_method_return_type" -type = "bin" -authors = [""] -compiler_version = "0.9.0" - -[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/Prover.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/Prover.toml deleted file mode 100644 index 2c1854573a4..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 1 -y = 2 diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/src/main.nr deleted file mode 100644 index 23e46430dbc..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_method_return_type/src/main.nr +++ /dev/null @@ -1,16 +0,0 @@ -trait Default { - fn default() -> Self; -} - -struct Foo { -} - -// This should fail to compile as `default()` should return `Foo` -impl Default for Foo { - fn default() -> Field { - x - } -} - -fn main() { -} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/Nargo.toml deleted file mode 100644 index 7299ec69e7a..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "trait_wrong_parameter" -type = "bin" -authors = [""] -compiler_version = "0.9.0" - -[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/Prover.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/Prover.toml deleted file mode 100644 index 2c1854573a4..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 1 -y = 2 diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/src/main.nr deleted file mode 100644 index ae7888e010f..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter/src/main.nr +++ /dev/null @@ -1,15 +0,0 @@ -trait FromField { - fn default(x: Field) -> Self; -} - -struct Foo { - bar: Field, -} - -impl Default for Foo { - fn default(x: u32) -> Self { - } -} - -fn main() { -} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/Nargo.toml deleted file mode 100644 index 95e3e222ca3..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "trait_wrong_method_return_type" -type = "bin" -authors = [""] -compiler_version = "0.9.0" - -[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/Prover.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/Prover.toml deleted file mode 100644 index 2c1854573a4..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 1 -y = 2 diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/src/main.nr deleted file mode 100644 index 2ba1ee13e70..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameter_type/src/main.nr +++ /dev/null @@ -1,7 +0,0 @@ -trait Default { - fn default(x: Field, y: NotAType) -> Field; -} - -fn main(x: Field, y: Field) { - assert(y == x); -} diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/Nargo.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/Nargo.toml deleted file mode 100644 index a60cf09e828..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "trait_wrong_parameters_count" -type = "bin" -authors = [""] -compiler_version = "0.9.0" - -[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/Prover.toml b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/Prover.toml deleted file mode 100644 index 2c1854573a4..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 1 -y = 2 diff --git a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/src/main.nr b/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/src/main.nr deleted file mode 100644 index 4d011ddf737..00000000000 --- a/tooling/nargo_cli/tests/compile_failure/trait_wrong_parameters_count/src/main.nr +++ /dev/null @@ -1,19 +0,0 @@ -use dep::std; - -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(x: Field, y: Field) { -} diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml b/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml new file mode 100644 index 00000000000..0dfaea44862 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "trait_self" +type = "bin" +authors = [""] +compiler_version = "0.10.5" + +[dependencies] \ No newline at end of file diff --git a/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr b/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr new file mode 100644 index 00000000000..f4f73822cc3 --- /dev/null +++ b/tooling/nargo_cli/tests/execution_success/trait_self/trait_self/src/main.nr @@ -0,0 +1,18 @@ +struct Foo { + x: Field +} + +trait Asd { + fn asd() -> Self; +} + +impl Asd for Foo { + // the Self should typecheck properly + fn asd() -> Self { + Foo{x: 100} + } +} + +fn main() { + assert(Foo::asd().x == 100); +} \ No newline at end of file