diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 110141008ea..39f48385b61 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -1164,10 +1164,17 @@ impl<'context> Elaborator<'context> { has_inline_attribute: bool, location: Location, ) { - if (is_entry_point && !typ.is_valid_for_program_input()) - || (has_inline_attribute && !typ.is_valid_non_inlined_function_input()) - { - self.push_err(TypeCheckError::InvalidTypeForEntryPoint { location }); + if is_entry_point { + if let Some(invalid_type) = typ.program_input_validity() { + self.push_err(TypeCheckError::InvalidTypeForEntryPoint { invalid_type, location }); + return; + } + } + + if has_inline_attribute { + if let Some(invalid_type) = typ.non_inlined_function_input_validity() { + self.push_err(TypeCheckError::InvalidTypeForEntryPoint { invalid_type, location }); + } } } diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 30a2ddf01d4..293e75713eb 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -15,6 +15,7 @@ use crate::hir_def::types::{BinaryTypeOperator, Kind, Type}; use crate::node_interner::NodeInterner; use crate::shared::Signedness; use crate::signed_field::SignedField; +use crate::validity::InvalidType; /// Rust also only shows 3 maximum, even for short patterns. pub const MAX_MISSING_CASES: usize = 3; @@ -208,7 +209,7 @@ pub enum TypeCheckError { #[error("Expected a constant, but found `{typ}`")] NonConstantEvaluated { typ: Type, location: Location }, #[error("Only sized types may be used in the entry point to a program")] - InvalidTypeForEntryPoint { location: Location }, + InvalidTypeForEntryPoint { invalid_type: InvalidType, location: Location }, #[error("Mismatched number of parameters in trait implementation")] MismatchTraitImplNumParameters { actual_num_parameters: usize, @@ -332,7 +333,7 @@ impl TypeCheckError { | TypeCheckError::Unsafe { location } | TypeCheckError::UnsafeFn { location } | TypeCheckError::NonConstantEvaluated { location, .. } - | TypeCheckError::InvalidTypeForEntryPoint { location } + | TypeCheckError::InvalidTypeForEntryPoint { location, .. } | TypeCheckError::MismatchTraitImplNumParameters { location, .. } | TypeCheckError::StringIndexAssign { location } | TypeCheckError::MacroReturningNonExpr { location, .. } @@ -627,9 +628,19 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { let msg = format!("Constraint for `{typ}: {trait_name}` is not needed, another matching impl is already in scope"); Diagnostic::simple_warning(msg, "Unnecessary trait constraint in where clause".into(), *location) } - TypeCheckError::InvalidTypeForEntryPoint { location } => Diagnostic::simple_error( - "Only sized types may be used in the entry point to a program".to_string(), - "Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions".to_string(), *location), + TypeCheckError::InvalidTypeForEntryPoint { invalid_type, location } => { + let primary_message = "Invalid type found in the entry point to a program".to_string(); + let mut diagnostic = Diagnostic::simple_error(primary_message, String::new(), *location); + diagnostic.secondaries.clear(); + + if matches!(invalid_type, InvalidType::StructField {..} | InvalidType::Alias {..}) { + diagnostic.add_secondary("This type has an invalid entry point type inside it".to_string(), *location); + } + + diagnostic.add_note("Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions.".to_string()); + add_invalid_type_to_diagnostic(invalid_type, *location, &mut diagnostic); + diagnostic + }, TypeCheckError::MismatchTraitImplNumParameters { expected_num_parameters, actual_num_parameters, @@ -816,3 +827,70 @@ impl NoMatchingImplFoundError { Some(Self { constraints, location }) } } + +fn add_invalid_type_to_diagnostic( + invalid_type: &InvalidType, + location: Location, + diagnostic: &mut Diagnostic, +) { + match invalid_type { + InvalidType::Primitive(typ) => match typ { + // Use a slightly better message for common types that might be used as entry point types + Type::Unit => { + diagnostic + .add_secondary("Unit is not a valid entry point type".to_string(), location); + } + Type::Reference(..) => { + diagnostic.add_secondary( + format!("Reference is not a valid entry point type. Found: {typ}"), + location, + ); + } + Type::Slice(..) => { + diagnostic.add_secondary( + format!("Slice is not a valid entry point type. Found: {typ}"), + location, + ); + } + _ => { + diagnostic.add_secondary(format!("Invalid entry point type: {typ}"), location); + } + }, + InvalidType::Enum(typ) => { + diagnostic.add_secondary( + format!("Enum is not yet allowed as an entry point type. Found: {typ}"), + location, + ); + } + InvalidType::EmptyArray(typ) => { + diagnostic.add_secondary( + format!("Empty array is not a valid entry point type. Found: {typ}"), + location, + ); + } + InvalidType::EmptyString(typ) => { + diagnostic.add_secondary( + format!("Empty string is not a valid entry point type. Found: {typ}"), + location, + ); + } + InvalidType::StructField { struct_name, field_name, invalid_type } => { + diagnostic.add_secondary( + format!("Struct {struct_name} has an invalid entry point type"), + struct_name.location(), + ); + diagnostic.add_secondary( + format!("Field {field_name} has an invalid entry point type"), + field_name.location(), + ); + add_invalid_type_to_diagnostic(invalid_type, field_name.location(), diagnostic); + } + InvalidType::Alias { alias_name, invalid_type } => { + diagnostic.add_secondary( + format!("Alias {alias_name} has an invalid entry point type"), + alias_name.location(), + ); + add_invalid_type_to_diagnostic(invalid_type, alias_name.location(), diagnostic); + } + } +} diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 5e598e4d700..5a52bb5895a 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -30,6 +30,7 @@ use super::traits::NamedType; mod arithmetic; mod unification; +pub(crate) mod validity; pub use unification::UnificationError; @@ -1352,193 +1353,6 @@ impl Type { matches!(self.follow_bindings_shallow().as_ref(), Type::Reference(_, _)) } - /// True if this type can be used as a parameter to `main` or a contract function. - /// This is only false for unsized types like slices or slices that do not make sense - /// as a program input such as named generics or mutable references. - /// - /// This function should match the same check done in `create_value_from_type` in acir_gen. - /// If this function does not catch a case where a type should be valid, it will later lead to a - /// panic in that function instead of a user-facing compiler error message. - pub(crate) fn is_valid_for_program_input(&self) -> bool { - match self { - // Type::Error is allowed as usual since it indicates an error was already issued and - // we don't need to issue further errors about this likely unresolved type - // TypeVariable and Generic are allowed here too as they can only result from - // generics being declared on the function itself, but we produce a different error in that case. - Type::FieldElement - | Type::Integer(_, _) - | Type::Bool - | Type::Constant(_, _) - | Type::TypeVariable(_) - | Type::NamedGeneric(_) - | Type::Error => true, - - Type::Unit - | Type::FmtString(_, _) - | Type::Function(_, _, _, _) - | Type::Reference(..) - | Type::Forall(_, _) - | Type::Quoted(_) - | Type::Slice(_) - | Type::TraitAsType(..) => false, - - Type::CheckedCast { to, .. } => to.is_valid_for_program_input(), - - Type::Alias(alias, generics) => { - let alias = alias.borrow(); - alias.get_type(generics).is_valid_for_program_input() - } - - Type::Array(length, element) => { - self.array_or_string_len_is_not_zero() - && length.is_valid_for_program_input() - && element.is_valid_for_program_input() - } - Type::String(length) => { - self.array_or_string_len_is_not_zero() && length.is_valid_for_program_input() - } - Type::Tuple(elements) => elements.iter().all(|elem| elem.is_valid_for_program_input()), - Type::DataType(definition, generics) => { - if let Some(fields) = definition.borrow().get_fields(generics) { - fields.into_iter().all(|(_, field, _)| field.is_valid_for_program_input()) - } else { - // Arbitrarily disallow enums from program input, though we may support them later - false - } - } - - Type::InfixExpr(lhs, _, rhs, _) => { - lhs.is_valid_for_program_input() && rhs.is_valid_for_program_input() - } - } - } - - /// Empty arrays and strings (which are arrays under the hood) are disallowed - /// as input to program entry points. - /// - /// The point of inputs to entry points is to process input data. - /// Thus, passing empty arrays is pointless and adds extra complexity to the compiler - /// for handling them. - fn array_or_string_len_is_not_zero(&self) -> bool { - match self { - Type::Array(length, _) | Type::String(length) => { - let length = length.evaluate_to_u32(Location::dummy()).unwrap_or(0); - length != 0 - } - _ => panic!("ICE: Expected an array or string type"), - } - } - - /// True if this type can be used as a parameter to an ACIR function that is not `main` or a contract function. - /// This encapsulates functions for which we may not want to inline during compilation. - /// - /// The inputs allowed for a function entry point differ from those allowed as input to a program as there are - /// certain types which through compilation we know what their size should be. - /// This includes types such as numeric generics. - pub(crate) fn is_valid_non_inlined_function_input(&self) -> bool { - match self { - // Type::Error is allowed as usual since it indicates an error was already issued and - // we don't need to issue further errors about this likely unresolved type - Type::FieldElement - | Type::Integer(_, _) - | Type::Bool - | Type::Unit - | Type::Constant(_, _) - | Type::TypeVariable(_) - | Type::NamedGeneric(_) - | Type::InfixExpr(..) - | Type::Error => true, - - Type::FmtString(_, _) - // To enable this we would need to determine the size of the closure outputs at compile-time. - // This is possible as long as the output size is not dependent upon a witness condition. - | Type::Function(_, _, _, _) - | Type::Slice(_) - | Type::Reference(..) - | Type::Forall(_, _) - // TODO: probably can allow code as it is all compile time - | Type::Quoted(_) - | Type::TraitAsType(..) => false, - - Type::CheckedCast { to, .. } => to.is_valid_non_inlined_function_input(), - - Type::Alias(alias, generics) => { - let alias = alias.borrow(); - alias.get_type(generics).is_valid_non_inlined_function_input() - } - - Type::Array(length, element) => { - length.is_valid_non_inlined_function_input() && element.is_valid_non_inlined_function_input() - } - Type::String(length) => length.is_valid_non_inlined_function_input(), - Type::Tuple(elements) => elements.iter().all(|elem| elem.is_valid_non_inlined_function_input()), - Type::DataType(definition, generics) => { - if let Some(fields) = definition.borrow().get_fields(generics) { - fields.into_iter() - .all(|(_, field, _)| field.is_valid_non_inlined_function_input()) - } else { - false - } - } - } - } - - /// Returns true if a value of this type can safely pass between constrained and - /// unconstrained functions (and vice-versa). - pub(crate) fn is_valid_for_unconstrained_boundary(&self) -> bool { - match self { - Type::FieldElement - | Type::Integer(_, _) - | Type::Bool - | Type::Unit - | Type::Constant(_, _) - | Type::Slice(_) - | Type::Function(_, _, _, _) - | Type::FmtString(_, _) - | Type::InfixExpr(..) - | Type::Error => true, - - Type::TypeVariable(type_var) | Type::NamedGeneric(NamedGeneric { type_var, .. }) => { - if let TypeBinding::Bound(typ) = &*type_var.borrow() { - typ.is_valid_for_unconstrained_boundary() - } else { - true - } - } - - Type::CheckedCast { to, .. } => to.is_valid_for_unconstrained_boundary(), - - // Quoted objects only exist at compile-time where the only execution - // environment is the interpreter. In this environment, they are valid. - Type::Quoted(_) => true, - - Type::Reference(..) | Type::Forall(_, _) | Type::TraitAsType(..) => false, - - Type::Alias(alias, generics) => { - let alias = alias.borrow(); - alias.get_type(generics).is_valid_for_unconstrained_boundary() - } - - Type::Array(length, element) => { - length.is_valid_for_unconstrained_boundary() - && element.is_valid_for_unconstrained_boundary() - } - Type::String(length) => length.is_valid_for_unconstrained_boundary(), - Type::Tuple(elements) => { - elements.iter().all(|elem| elem.is_valid_for_unconstrained_boundary()) - } - Type::DataType(definition, generics) => { - if let Some(fields) = definition.borrow().get_fields(generics) { - fields - .into_iter() - .all(|(_, field, _)| field.is_valid_for_unconstrained_boundary()) - } else { - false - } - } - } - } - /// Returns the number of `Forall`-quantified type variables on this type. /// Returns 0 if this is not a Type::Forall pub fn generic_count(&self) -> usize { diff --git a/compiler/noirc_frontend/src/hir_def/types/validity.rs b/compiler/noirc_frontend/src/hir_def/types/validity.rs new file mode 100644 index 00000000000..3ef8413ac94 --- /dev/null +++ b/compiler/noirc_frontend/src/hir_def/types/validity.rs @@ -0,0 +1,252 @@ +use noirc_errors::Location; + +use crate::{NamedGeneric, Type, TypeBinding, ast::Ident}; + +/// An type incorrectly used as a program input. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum InvalidType { + Primitive(Type), + Enum(Type), + EmptyArray(Type), + EmptyString(Type), + Alias { alias_name: Ident, invalid_type: Box }, + StructField { struct_name: Ident, field_name: Ident, invalid_type: Box }, +} + +impl Type { + /// Returns this type, or a nested one, that cannot be used as a parameter to `main` + /// or a contract function. + /// This is only Some for unsized types like slices or slices that do not make sense + /// as a program input such as named generics or mutable references. + /// + /// This function should match the same check done in `create_value_from_type` in acir_gen. + /// If this function does not catch a case where a type should be valid, it will later lead to a + /// panic in that function instead of a user-facing compiler error message. + /// + /// Returns `None` if this type and its nested types are all valid program inputs. + pub(crate) fn program_input_validity(&self) -> Option { + match self { + // Type::Error is allowed as usual since it indicates an error was already issued and + // we don't need to issue further errors about this likely unresolved type + // TypeVariable and Generic are allowed here too as they can only result from + // generics being declared on the function itself, but we produce a different error in that case. + Type::FieldElement + | Type::Integer(_, _) + | Type::Bool + | Type::Constant(_, _) + | Type::TypeVariable(_) + | Type::NamedGeneric(_) + | Type::Error => None, + + Type::Unit + | Type::FmtString(_, _) + | Type::Function(_, _, _, _) + | Type::Reference(..) + | Type::Forall(_, _) + | Type::Quoted(_) + | Type::Slice(_) + | Type::TraitAsType(..) => Some(InvalidType::Primitive(self.clone())), + + Type::CheckedCast { to, .. } => to.program_input_validity(), + + Type::Alias(alias, generics) => { + let alias = alias.borrow(); + if let Some(invalid_type) = alias.get_type(generics).program_input_validity() { + let alias_name = alias.name.clone(); + Some(InvalidType::Alias { alias_name, invalid_type: Box::new(invalid_type) }) + } else { + None + } + } + + Type::Array(length, element) => { + if length_is_zero(length) { + Some(InvalidType::EmptyArray(self.clone())) + } else { + length.program_input_validity().or_else(|| element.program_input_validity()) + } + } + Type::String(length) => { + if length_is_zero(length) { + Some(InvalidType::EmptyString(self.clone())) + } else { + length.program_input_validity() + } + } + Type::Tuple(elements) => { + for element in elements { + if let Some(invalid_type) = element.program_input_validity() { + return Some(invalid_type); + } + } + None + } + Type::DataType(definition, generics) => { + let definition = definition.borrow(); + + if let Some(fields) = definition.get_fields(generics) { + for (field_name, field, _) in fields { + if let Some(invalid_type) = field.program_input_validity() { + let struct_name = definition.name.clone(); + let mut fields_raw = definition.fields_raw().unwrap().iter(); + let field = fields_raw.find(|field| field.name.as_str() == field_name); + return Some(InvalidType::StructField { + struct_name, + field_name: field.unwrap().name.clone(), + invalid_type: Box::new(invalid_type), + }); + } + } + None + } else { + // Arbitrarily disallow enums from program input, though we may support them later + Some(InvalidType::Enum(self.clone())) + } + } + + Type::InfixExpr(lhs, _, rhs, _) => { + lhs.program_input_validity().or_else(|| rhs.program_input_validity()) + } + } + } + + /// Returns this type, or a nested one, if this type can be used as a parameter to an ACIR + /// function that is not `main` or a contract function. + /// This encapsulates functions for which we may not want to inline during compilation. + /// + /// The inputs allowed for a function entry point differ from those allowed as input to a program as there are + /// certain types which through compilation we know what their size should be. + /// This includes types such as numeric generics. + pub(crate) fn non_inlined_function_input_validity(&self) -> Option { + match self { + // Type::Error is allowed as usual since it indicates an error was already issued and + // we don't need to issue further errors about this likely unresolved type + Type::FieldElement + | Type::Integer(_, _) + | Type::Bool + | Type::Unit + | Type::Constant(_, _) + | Type::TypeVariable(_) + | Type::NamedGeneric(_) + | Type::InfixExpr(..) + | Type::Error => None, + + Type::FmtString(_, _) + // To enable this we would need to determine the size of the closure outputs at compile-time. + // This is possible as long as the output size is not dependent upon a witness condition. + | Type::Function(_, _, _, _) + | Type::Slice(_) + | Type::Reference(..) + | Type::Forall(_, _) + // TODO: probably can allow code as it is all compile time + | Type::Quoted(_) + | Type::TraitAsType(..) => Some(InvalidType::Primitive(self.clone())), + + Type::CheckedCast { to, .. } => to.non_inlined_function_input_validity(), + + Type::Alias(alias, generics) => { + let alias = alias.borrow(); + if let Some(invalid_type) = alias.get_type(generics).non_inlined_function_input_validity() { + let alias_name = alias.name.clone(); + Some(InvalidType::Alias { alias_name, invalid_type: Box::new(invalid_type) }) + } else { + None + } + } + + Type::Array(length, element) => { + length.non_inlined_function_input_validity().or_else(|| element.non_inlined_function_input_validity()) + } + Type::String(length) => length.non_inlined_function_input_validity(), + Type::Tuple(elements) => { + for element in elements { + if let Some(invalid_type) = element.non_inlined_function_input_validity() { + return Some(invalid_type); + } + } + None + }, + Type::DataType(definition, generics) => { + let definition = definition.borrow(); + + if let Some(fields) = definition.get_fields(generics) { + for (field_name, field, _) in fields { + if let Some(invalid_type) = field.non_inlined_function_input_validity() { + let struct_name = definition.name.clone(); + let mut fields_raw = definition.fields_raw().unwrap().iter(); + let field = fields_raw.find(|field| field.name.as_str() == field_name); + return Some(InvalidType::StructField { + struct_name, + field_name: field.unwrap().name.clone(), + invalid_type: Box::new(invalid_type), + }); + } + } + None + } else { + Some(InvalidType::Enum(self.clone())) + } + } + } + } + + /// Returns true if a value of this type can safely pass between constrained and + /// unconstrained functions (and vice-versa). + pub(crate) fn is_valid_for_unconstrained_boundary(&self) -> bool { + match self { + Type::FieldElement + | Type::Integer(_, _) + | Type::Bool + | Type::Unit + | Type::Constant(_, _) + | Type::Slice(_) + | Type::Function(_, _, _, _) + | Type::FmtString(_, _) + | Type::InfixExpr(..) + | Type::Error => true, + + Type::TypeVariable(type_var) | Type::NamedGeneric(NamedGeneric { type_var, .. }) => { + if let TypeBinding::Bound(typ) = &*type_var.borrow() { + typ.is_valid_for_unconstrained_boundary() + } else { + true + } + } + + Type::CheckedCast { to, .. } => to.is_valid_for_unconstrained_boundary(), + + // Quoted objects only exist at compile-time where the only execution + // environment is the interpreter. In this environment, they are valid. + Type::Quoted(_) => true, + + Type::Reference(..) | Type::Forall(_, _) | Type::TraitAsType(..) => false, + + Type::Alias(alias, generics) => { + let alias = alias.borrow(); + alias.get_type(generics).is_valid_for_unconstrained_boundary() + } + + Type::Array(length, element) => { + length.is_valid_for_unconstrained_boundary() + && element.is_valid_for_unconstrained_boundary() + } + Type::String(length) => length.is_valid_for_unconstrained_boundary(), + Type::Tuple(elements) => { + elements.iter().all(|elem| elem.is_valid_for_unconstrained_boundary()) + } + Type::DataType(definition, generics) => { + if let Some(fields) = definition.borrow().get_fields(generics) { + fields + .into_iter() + .all(|(_, field, _)| field.is_valid_for_unconstrained_boundary()) + } else { + false + } + } + } + } +} + +fn length_is_zero(length: &Type) -> bool { + length.evaluate_to_u32(Location::dummy()).unwrap_or(0) == 0 +} diff --git a/test_programs/compile_failure/invalid_entry_point_type/Nargo.toml b/test_programs/compile_failure/invalid_entry_point_type/Nargo.toml new file mode 100644 index 00000000000..78a516a1d5a --- /dev/null +++ b/test_programs/compile_failure/invalid_entry_point_type/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "invalid_entry_point_type" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/compile_failure/invalid_entry_point_type/src/main.nr b/test_programs/compile_failure/invalid_entry_point_type/src/main.nr new file mode 100644 index 00000000000..4816b5fc54d --- /dev/null +++ b/test_programs/compile_failure/invalid_entry_point_type/src/main.nr @@ -0,0 +1,11 @@ +struct Foo { + bar: Bar, +} + +struct Bar { + baz: [Field], +} + +type SomeAlias = Foo; + +fn main(_: SomeAlias) {} diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/array_oob_regression_7952/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/array_oob_regression_7952/execute__tests__stderr.snap index 01a78bf93f4..a30a1a88d6e 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_failure/array_oob_regression_7952/execute__tests__stderr.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/array_oob_regression_7952/execute__tests__stderr.snap @@ -2,11 +2,12 @@ source: tooling/nargo_cli/tests/execute.rs expression: stderr --- -error: Only sized types may be used in the entry point to a program +error: Invalid type found in the entry point to a program ┌─ src/main.nr:1:12 │ 1 │ fn main(a: [[u32; 0]; 1], b: bool) -> pub [u32; 0] { - │ ------------- Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions + │ ------------- Empty array is not a valid entry point type. Found: [u32; 0] │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. Aborting due to 1 previous error diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/databus_dead_param/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/databus_dead_param/execute__tests__stderr.snap index eb6e25ceb72..7226daf1ce9 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_failure/databus_dead_param/execute__tests__stderr.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/databus_dead_param/execute__tests__stderr.snap @@ -2,11 +2,12 @@ source: tooling/nargo_cli/tests/execute.rs expression: stderr --- -error: Only sized types may be used in the entry point to a program +error: Invalid type found in the entry point to a program ┌─ src/main.nr:4:22 │ 4 │ _b: call_data(0) [(i8, i8, bool, bool, str<0>); 2], - │ --------------------------------- Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions + │ --------------------------------- Empty string is not a valid entry point type. Found: str<0> │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. Aborting due to 1 previous error diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/databus_in_fn_with_empty_arr/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/databus_in_fn_with_empty_arr/execute__tests__stderr.snap index 8370105c23b..68231536e2d 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_failure/databus_in_fn_with_empty_arr/execute__tests__stderr.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/databus_in_fn_with_empty_arr/execute__tests__stderr.snap @@ -2,11 +2,12 @@ source: tooling/nargo_cli/tests/execute.rs expression: stderr --- -error: Only sized types may be used in the entry point to a program +error: Invalid type found in the entry point to a program ┌─ src/main.nr:1:17 │ 1 │ fn main(_empty: [u32; 0], value_1: u32, value_2: call_data(0) u32) { - │ -------- Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions + │ -------- Empty array is not a valid entry point type. Found: [u32; 0] │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. Aborting due to 1 previous error diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/invalid_entry_point_type/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/invalid_entry_point_type/execute__tests__stderr.snap new file mode 100644 index 00000000000..38b87b30a4b --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/invalid_entry_point_type/execute__tests__stderr.snap @@ -0,0 +1,29 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stderr +--- +error: Invalid type found in the entry point to a program + ┌─ src/main.nr:1:8 + │ + 1 │ struct Foo { + │ --- Struct Foo has an invalid entry point type + 2 │ bar: Bar, + │ --- Field bar has an invalid entry point type + · + 5 │ struct Bar { + │ --- Struct Bar has an invalid entry point type + 6 │ baz: [Field], + │ --- + │ │ + │ Field baz has an invalid entry point type + │ Slice is not a valid entry point type. Found: [Field] + · + 9 │ type SomeAlias = Foo; + │ --------- Alias SomeAlias has an invalid entry point type +10 │ +11 │ fn main(_: SomeAlias) {} + │ --------- This type has an invalid entry point type inside it + │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. + +Aborting due to 1 previous error diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/main_with_generics/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/main_with_generics/execute__tests__stderr.snap index 7f0a27f39ee..9d74f036575 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_failure/main_with_generics/execute__tests__stderr.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/main_with_generics/execute__tests__stderr.snap @@ -9,11 +9,12 @@ error: `main` entry-point function is not allowed to have generic parameters │ ------ │ -error: Only sized types may be used in the entry point to a program +error: Invalid type found in the entry point to a program ┌─ src/main.nr:1:24 │ 1 │ fn main(x: [Field; F]) { - │ ---------- Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions + │ ---------- Empty array is not a valid entry point type. Found: [Field; F] │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. Aborting due to 2 previous errors diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/test_invalid_argument_type/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/test_invalid_argument_type/execute__tests__stderr.snap index 182ac755cb8..93b25d405d9 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_failure/test_invalid_argument_type/execute__tests__stderr.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/test_invalid_argument_type/execute__tests__stderr.snap @@ -2,11 +2,12 @@ source: tooling/nargo_cli/tests/execute.rs expression: stderr --- -error: Only sized types may be used in the entry point to a program +error: Invalid type found in the entry point to a program ┌─ src/main.nr:4:15 │ 4 │ fn test(_arg: &mut i32) {} - │ -------- Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions + │ -------- Reference is not a valid entry point type. Found: &mut i32 │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. Aborting due to 1 previous error diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/unit_in_main/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/unit_in_main/execute__tests__stderr.snap index 27732808d2a..54edb98d02c 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_failure/unit_in_main/execute__tests__stderr.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/unit_in_main/execute__tests__stderr.snap @@ -2,11 +2,12 @@ source: tooling/nargo_cli/tests/execute.rs expression: stderr --- -error: Only sized types may be used in the entry point to a program +error: Invalid type found in the entry point to a program ┌─ src/main.nr:1:12 │ 1 │ fn main(_: ()) {} - │ -- Slices, references, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions + │ -- Unit is not a valid entry point type │ + = Note: slices, references, empty arrays, empty strings, or any type containing them may not be used in main, contract functions, test functions, fuzz functions or foldable functions. Aborting due to 1 previous error