diff --git a/compiler/noirc_frontend/src/elaborator/trait_impls.rs b/compiler/noirc_frontend/src/elaborator/trait_impls.rs index 15f37d5ca37..faa313dfa8f 100644 --- a/compiler/noirc_frontend/src/elaborator/trait_impls.rs +++ b/compiler/noirc_frontend/src/elaborator/trait_impls.rs @@ -1156,7 +1156,7 @@ impl Elaborator<'_> { // This way associated types can be referred to even if their actual value (for associated constants) // is not known yet. This is to allow associated constants to refer to associated constants // in other trait impls. - let object = trait_impl.object_type.to_string(); + let object = self.unresolved_type_name(&trait_impl.object_type); let trait_name = trait_id.map(|id| self.interner.get_trait(id).name.to_string()); let associated_types_behind_type_vars = vecmap(&associated_types, |(name, _typ, kind)| { let new_generic_id = self.interner.next_type_variable_id(); diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index f9714172763..6e4b4f2d729 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -174,7 +174,8 @@ use itertools::Itertools; use noirc_errors::Location; use crate::{ - Kind, NamedGeneric, ResolvedGeneric, Type, TypeBindings, TypeVariable, + IMPL_TRAIT_PARAMETER_NAME_PREFIX, Kind, NamedGeneric, ResolvedGeneric, Type, TypeBindings, + TypeVariable, ast::{ FunctionDefinition, FunctionKind, GenericTypeArgs, Ident, NoirFunction, Path, TraitBound, TraitItem, UnresolvedGeneric, UnresolvedTraitConstraint, UnresolvedType, @@ -444,7 +445,7 @@ impl Elaborator<'_> { let the_trait = self.get_trait(trait_id); let trait_name = the_trait.name.to_string(); - let object_name = object.to_string(); + let object_name = self.unresolved_type_name(object); let associated_type_bounds = the_trait.associated_type_bounds.clone(); for associated_type in &the_trait.associated_types.clone() { @@ -520,7 +521,7 @@ impl Elaborator<'_> { let new_generic = TypeVariable::unbound(new_generic_id, Kind::Normal); generics.push(new_generic.clone()); - let name = format!("impl {trait_path}"); + let name = format!("{IMPL_TRAIT_PARAMETER_NAME_PREFIX}{trait_path}"); let generic_type = new_generic.into_named_generic(&Rc::new(name), None); let trait_bound = TraitBound { trait_path, trait_generics }; diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 08f26f989e1..843d11cabff 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -127,6 +127,26 @@ impl Elaborator<'_> { ) } + /// Stringifies a type as written, for embedding in an associated type's name + /// (`"<{object} as {trait}>::{name}"`). A macro-spliced type arrives already resolved and + /// its `Display` is the "(resolved type)" placeholder, so look through the resolution to + /// the actual type. These names resurface in `nargo expand` output, where the placeholder + /// would not parse. + /// + /// Note that `Display` for a resolved [Type] is not source-faithful: data types print as + /// their bare name (no module path, so a same-named type in scope at the printing site can + /// shadow it) and unbound type variables print as `_` or their kind's default. These names + /// are display-only — nothing semantic keys off them — but the printed projection may not + /// re-resolve in every context. + pub(super) fn unresolved_type_name(&self, typ: &UnresolvedType) -> String { + match &typ.typ { + UnresolvedTypeData::Resolved(quoted_type_id) => { + self.interner.get_quoted_type(*quoted_type_id).to_string() + } + _ => typ.to_string(), + } + } + /// Resolves an [`UnresolvedType`] to a [Type] with [`Kind::Normal`] and marks it, and any generic types it contains, as _used_. #[tracing::instrument(level = "trace", skip_all)] pub(crate) fn use_type( diff --git a/compiler/noirc_frontend/src/hir/printer/items/hir_def.rs b/compiler/noirc_frontend/src/hir/printer/items/hir_def.rs index 4b8cae410e6..b34d35de9a9 100644 --- a/compiler/noirc_frontend/src/hir/printer/items/hir_def.rs +++ b/compiler/noirc_frontend/src/hir/printer/items/hir_def.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use itertools::Itertools; use crate::{ - NamedGeneric, Type, TypeBindings, + Kind, NamedGeneric, Type, TypeBinding, TypeBindings, ast::{ItemVisibility, UnaryOp}, hir::def_map::ModuleDefId, hir_def::{ @@ -857,7 +857,15 @@ impl ItemPrinter<'_, '_> { } else { match &constraint.typ { Type::TypeVariable(type_var) if type_var.borrow().is_unbound() => { - // Don't show this as `AsTraitPath` + // The trait's own `Self` type variable can only stay unbound inside + // that trait's body, where the item is reachable as `Self::item`. + if self.trait_self_typevar == Some(type_var.id()) { + self.push_str("Self::"); + let name = self.interner.definition_name(trait_item.definition); + self.push_str(name); + return; + } + // Otherwise don't show this as `AsTraitPath` } _ => { self.push('<'); @@ -950,9 +958,71 @@ impl ItemPrinter<'_, '_> { use_import, ); } - DefinitionKind::Local(..) - | DefinitionKind::NumericGeneric(..) - | DefinitionKind::AssociatedConstant(..) => { + DefinitionKind::AssociatedConstant(trait_impl_id, ref name) => { + // The bare name only resolves inside the trait impl that defines the constant, + // so qualify it: `Self::N` within that impl, `::N` elsewhere. + let trait_impl = self.interner.get_trait_implementation(trait_impl_id); + let trait_impl = trait_impl.borrow(); + if self.self_type.as_ref() == Some(&trait_impl.typ) { + self.push_str("Self::"); + } else { + // The qualified form `::N` names the trait; when the trait + // isn't visible from this module (e.g. the reference was spliced in by a + // comptime `Expr::resolve` in another module's scope), print the constant's + // compile-time value instead. + let module_def_id = ModuleDefId::TraitId(trait_impl.trait_id); + let trait_ = self.interner.get_trait(trait_impl.trait_id); + let trait_is_visible = self + .module_def_id_is_visible_or_reexported(module_def_id, trait_.visibility); + if !trait_is_visible + && let Some(named_type) = self + .interner + .get_associated_types_for_impl(trait_impl_id) + .iter() + .find(|named_type| named_type.name.as_str() == name) + && let Type::Constant(constant) = named_type.typ.follow_bindings() + { + self.push_str(&constant.to_string()); + if let Kind::Numeric(numeric_type) = named_type.typ.kind() { + self.push('_'); + self.show_type(&numeric_type); + } + return; + } + self.push('<'); + self.show_type(&trait_impl.typ); + self.push_str(" as "); + let trait_ = self.interner.get_trait(trait_impl.trait_id); + self.show_reference_to_module_def_id( + ModuleDefId::TraitId(trait_impl.trait_id), + trait_.visibility, + true, + ); + let trait_generics = self.interner.get_trait_generics_for_impl(trait_impl_id); + let use_colons = false; + self.show_generic_types(&trait_generics.ordered, use_colons); + self.push_str(">::"); + } + self.push_str(name); + } + DefinitionKind::NumericGeneric(ref type_var, ref numeric_type) => { + // When a numeric type alias's parameter is used as a value (`AliasN::<1>`), + // the definition's type variable is bound to the resolved value and the bare + // name doesn't resolve at the use site (or worse, resolves to something else + // with the same name). Print the value instead, suffixed with its numeric + // type so it can't be inferred as a different one. + if let TypeBinding::Bound(binding) = &*type_var.borrow() + && let Type::Constant(constant) = binding.follow_bindings() + { + self.push_str(&constant.to_string()); + self.push('_'); + self.show_type(numeric_type); + return; + } + let name = self.interner.definition_name(ident.id); + self.push_str(name); + } + DefinitionKind::Local(..) => { let name = self.interner.definition_name(ident.id); // The compiler uses '$' for some internal identifiers. diff --git a/compiler/noirc_frontend/src/hir/printer/mod.rs b/compiler/noirc_frontend/src/hir/printer/mod.rs index de473e5daf9..85cbface865 100644 --- a/compiler/noirc_frontend/src/hir/printer/mod.rs +++ b/compiler/noirc_frontend/src/hir/printer/mod.rs @@ -3,10 +3,10 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use crate::graph::{CrateGraph, CrateId}; use crate::hir::comptime::FormatStringFragment; use crate::hir::printer::items::ItemBuilder; -use crate::hir::resolution::visibility::module_def_id_visibility; +use crate::hir::resolution::visibility::{module_def_id_visibility, struct_member_is_visible}; use crate::node_interner::TraitImplId; use crate::{ - DataType, Kind, NamedGeneric, ResolvedGenerics, Type, + DataType, Kind, NamedGeneric, ResolvedGenerics, Type, TypeVariableId, ast::{DocComment, Ident, ItemVisibility}, graph::Dependency, hir::{ @@ -16,11 +16,14 @@ use crate::{ }, hir_def::{ expr::HirExpression, + function::FuncMeta, stmt::{HirLetStatement, HirPattern}, traits::{ResolvedTraitBound, TraitConstraint}, }, modules::{get_parent_module, module_def_id_is_visible, module_def_id_to_reference_id}, - node_interner::{FuncId, GlobalId, GlobalValue, NodeInterner, ReferenceId, TypeAliasId}, + node_interner::{ + FuncId, GlobalId, GlobalValue, NodeInterner, ReferenceId, TypeAliasId, TypeId, + }, shared::Visibility, token::{FunctionAttributeKind, LocatedToken, SecondaryAttribute, SecondaryAttributeKind}, }; @@ -89,6 +92,11 @@ struct ItemPrinter<'context, 'string> { imports: HashMap, self_type: Option, + /// When printing the body of a trait, this is the trait's `Self` type variable. + /// Any unbound occurrence of it (for example in `Self::method()` inside a default + /// method) must be printed as `Self`, which is the only name it has in source. + trait_self_typevar: Option, + /// Trait constraints in scope from an enclosing trait, trait impl, inherent impl, or /// function. A method's own where clause is filtered against these (see /// [`Self::parent_constraints_contain`]) so constraints already shown on the enclosing item @@ -122,6 +130,7 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { module_id, imports, self_type: None, + trait_self_typevar: None, trait_constraints: Vec::new(), trait_impls_printed: HashSet::new(), } @@ -416,6 +425,12 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { self.push_str("type "); self.push_str(&type_alias.name.to_string()); self.show_generics(&type_alias.generics); + // A numeric type alias (`type Double: u32 = N * 2;`) must spell out its + // numeric type, otherwise the right-hand side is rejected as a type expression. + if let Kind::Numeric(numeric_type) = type_alias.typ.kind() { + self.push_str(": "); + self.show_type(&numeric_type); + } self.push_str(" = "); self.show_type(&type_alias.typ); self.push(';'); @@ -448,6 +463,7 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { self.increase_indent(); self.trait_constraints = trait_.where_clause.clone(); + self.trait_self_typevar = Some(trait_.self_type_typevar.id()); let mut printed_type_or_function = false; @@ -498,6 +514,7 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { self.push('}'); self.trait_constraints.clear(); + self.trait_self_typevar = None; // Only show trait impls for types outside of the current crate: // trait impls for types in this crate are already shown alongside the type definition. @@ -558,14 +575,29 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { self.push_str("let "); self.push_str(&named_type.name.to_string()); self.push_str(": "); + // `Self` doesn't resolve in an associated constant's numeric type annotation, + // so print the type itself even when it's the impl's self type. This covers + // the whole declaration — annotation, value and the value's type suffix — + // since the value is a numeric type expression subject to the same rule. + let self_type = self.self_type.take(); self.show_type(&numeric_type); self.push_str(" = "); + // An unsuffixed literal in this position is checked as `u32`, so a constant + // of any other numeric type needs its type suffix. + if let Type::Constant(constant) = named_type.typ.follow_bindings() { + self.push_str(&constant.to_string()); + self.push('_'); + self.show_type(&numeric_type); + } else { + self.show_type(&named_type.typ); + } + self.self_type = self_type; } else { self.push_str("type "); self.push_str(&named_type.name.to_string()); self.push_str(" = "); + self.show_type(&named_type.typ); } - self.show_type(&named_type.typ); self.push_str(";"); printed_item = true; @@ -617,11 +649,165 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { self.push_str(&global_info.ident.to_string()); self.push_str(": "); self.show_type(&typ); + let mut initializer_may_differ_from_value = false; if let GlobalValue::Resolved(value) = &global_info.value { self.push_str(" = "); - self.show_value(value); + // Prefer the evaluated value: a comptime-mutable global's final value can differ + // from what its initializer evaluates to. But some values can't be reconstructed + // as source code (private struct fields, comptime-only values): for those, print + // the original initializer expression, which is at least as visible as it was in + // the original program. + if self.value_is_representable(value) { + self.show_value(value); + } else if let Some(let_statement) = self.interner.get_global_let_statement(global_id) { + // For a mutable global the mutations happened via attributes and comptime + // blocks that are already expanded away, so re-evaluating the initializer + // does not reproduce the final value. + initializer_may_differ_from_value = definition.mutable; + let expr_id = let_statement.expression; + let hir_expr = self.interner.expression(&expr_id); + self.show_hir_expression(hir_expr, expr_id); + } else { + self.show_value(value); + } } self.push_str(";"); + if initializer_may_differ_from_value { + self.push_str( + " // Warning: this global was mutated at compile time; its final value could not be printed, so this is its initializer", + ); + } + } + + /// Whether [`Self::show_value`] can print `value` as source code that compiles from the + /// current module. Some values have no code representation at all (they print as a + /// `panic(...)` placeholder), and a struct literal only compiles where the struct's type + /// and all of its fields are visible. + fn value_is_representable(&self, value: &Value) -> bool { + match value { + Value::Unit + | Value::Bool(_) + | Value::Integer(_) + | Value::Quoted(_) + | Value::Zeroed(_) => true, + + Value::Function(func_id, ..) => self.function_is_visible(*func_id), + + // A closure prints as just its lambda, so any captured variables would be + // dangling references at the global's scope. + Value::Closure(closure) => closure.lambda.captures.is_empty(), + + Value::String(bytes) | Value::CtString(bytes) => string_bytes_are_representable(bytes), + + Value::FormatString(fragments, ..) => fragments.iter().all(|fragment| match fragment { + FormatStringFragment::String(string) => { + format_string_fragment_is_representable(string) + } + FormatStringFragment::Value { value, .. } => self.value_is_representable(value), + }), + + Value::Tuple(values) => { + values.iter().all(|value| self.value_is_representable(&value.borrow())) + } + + Value::Struct(fields, typ) => { + self.struct_literal_is_visible(typ) + && fields.values().all(|value| self.value_is_representable(&value.borrow())) + } + + Value::Enum(_, args, typ) => { + self.data_type_is_visible(typ) + && args.iter().all(|arg| self.value_is_representable(arg)) + } + + Value::Array(values, _) | Value::Vector(values, _) => { + values.iter().all(|value| self.value_is_representable(value)) + } + + Value::Pointer(value, ..) => self.value_is_representable(&value.borrow()), + + // These print as a `panic(...)` placeholder (see `show_value`). + Value::TypeDefinition(_) + | Value::TraitConstraint(..) + | Value::TraitDefinition(_) + | Value::TraitImpl(_) + | Value::FunctionDefinition(_) + | Value::ModuleDefinition(_) + | Value::Type(_) + | Value::Expr(_) + | Value::TypedExpr(_) + | Value::UnresolvedType(_) + | Value::Location(_) => false, + } + } + + /// Whether a struct literal of the given type compiles from the current module: + /// the type itself and every field must be visible. + fn struct_literal_is_visible(&self, typ: &Type) -> bool { + let typ = typ.follow_bindings(); + let Type::DataType(data_type, generics) = &typ else { + return true; + }; + let data_type = data_type.borrow(); + if !self.data_type_id_is_visible(data_type.id, data_type.visibility) { + return false; + } + let Some(fields) = data_type.get_fields(generics) else { + return false; + }; + fields.iter().all(|(_, _, visibility)| { + struct_member_is_visible(data_type.id, *visibility, self.module_id, self.def_maps) + }) + } + + /// Whether the given data type (by name) is visible from the current module. + fn data_type_is_visible(&self, typ: &Type) -> bool { + let typ = typ.follow_bindings(); + let Type::DataType(data_type, _) = &typ else { + return true; + }; + let data_type = data_type.borrow(); + self.data_type_id_is_visible(data_type.id, data_type.visibility) + } + + fn data_type_id_is_visible(&self, id: TypeId, visibility: ItemVisibility) -> bool { + let module_def_id = ModuleDefId::TypeId(id); + self.module_def_id_is_visible_or_reexported(module_def_id, visibility) + } + + /// Whether a reference to the given function compiles from the current module. Methods + /// (impl, trait impl or trait functions) are printed as `Type::method` or + /// `::method`, whose visibility follows the container, so only plain + /// functions are checked here. + fn function_is_visible(&self, func_id: FuncId) -> bool { + let func_meta = self.interner.function_meta(&func_id); + if func_meta.trait_impl.is_some() + || func_meta.trait_id.is_some() + || func_meta.type_id.is_some() + { + return true; + } + let visibility = self.interner.function_visibility(func_id); + self.module_def_id_is_visible_or_reexported(ModuleDefId::FunctionId(func_id), visibility) + } + + /// This over-approximates on purpose: a re-export *somewhere* isn't necessarily nameable + /// from this module, but it matches what `show_reference_to_module_def_id` does — when an + /// item isn't directly visible it prints through the first re-export it finds. + fn module_def_id_is_visible_or_reexported( + &self, + module_def_id: ModuleDefId, + visibility: ItemVisibility, + ) -> bool { + module_def_id_is_visible( + module_def_id, + self.module_id, + visibility, + None, + self.interner, + self.def_maps, + self.dependencies, + ) || !self.interner.get_reexports(module_def_id).is_empty() } /// Whether a constraint already in scope from an enclosing item subsumes the given one, so @@ -677,7 +863,16 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { if matches!(visibility, Visibility::Public) { self.push_str("pub "); } - self.show_type(typ); + + // An `impl Trait` parameter desugars to a hidden generic whose synthetic name + // omits the trait's generic arguments (see `desugar_impl_trait_arg`), so it is + // printed from its resolved trait constraint instead. + if let Some(constraint) = impl_trait_parameter_constraint(func_meta, typ) { + self.push_str("impl "); + self.show_trait_bound(&constraint.trait_bound); + } else { + self.show_type(typ); + } } if index != parameters.len() - 1 { @@ -705,7 +900,20 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { .cloned() .collect::>(); - self.show_where_clause(&func_trait_constraints); + // An `impl Trait` parameter desugars to a hidden generic named `impl {Trait}` with a + // trait constraint (see `desugar_impl_trait_arg`). That constraint is implied by the + // parameter type itself and its synthetic name is not valid in a where clause, so it + // must not be printed. + let shown_trait_constraints = func_trait_constraints + .iter() + .filter(|constraint| { + !matches!(&constraint.typ, + Type::NamedGeneric(generic) if generic.is_impl_trait_parameter()) + }) + .cloned() + .collect::>(); + + self.show_where_clause(&shown_trait_constraints); let previous_trait_constraints_length = self.trait_constraints.len(); self.trait_constraints.extend(func_trait_constraints); @@ -1420,3 +1628,56 @@ impl<'context, 'string> ItemPrinter<'context, 'string> { self.string.push(char); } } + +/// If `typ` is the hidden generic minted for an `impl Trait` parameter, returns the trait +/// constraint that was desugared alongside it (see `desugar_impl_trait_arg`). The synthetic +/// generic's name omits the trait's generic arguments, so printing the parameter faithfully +/// requires the resolved bound instead. +fn impl_trait_parameter_constraint<'meta>( + func_meta: &'meta FuncMeta, + typ: &Type, +) -> Option<&'meta TraitConstraint> { + let Type::NamedGeneric(generic) = typ else { + return None; + }; + if !generic.is_impl_trait_parameter() { + return None; + } + func_meta.trait_constraints.iter().find(|constraint| { + matches!(&constraint.typ, + Type::NamedGeneric(constraint_generic) + if constraint_generic.type_var.id() == generic.type_var.id()) + }) +} + +/// Whether `show_value` can print these string bytes as a `"..."` literal that lexes back to +/// the same bytes. The bytes must be valid UTF-8, and every character must survive the trip +/// through Rust's `{:?}` formatting: Rust escapes control characters, combining marks and +/// other special characters as `\u{..}`, which Noir's lexer doesn't accept (it only knows +/// `\r \n \t \0 \" \\`). +fn string_bytes_are_representable(bytes: &[u8]) -> bool { + let Ok(string) = std::str::from_utf8(bytes) else { + return false; + }; + string.chars().all(char_survives_debug_formatting) +} + +fn char_survives_debug_formatting(char: char) -> bool { + // `{:?}` on a string prints `'` unescaped, even though `char::escape_debug` escapes it. + if char == '\'' { + return true; + } + let mut escaped = char.escape_debug(); + match escaped.next() { + // The escapes Noir's lexer accepts; anything else (i.e. `\u{..}`) doesn't re-lex. + Some('\\') => matches!(escaped.next(), Some('r' | 'n' | 't' | '0' | '"' | '\\')), + _ => true, + } +} + +/// Whether `show_value` can print this format string fragment inside an `f"..."` literal. +/// Fragments are printed raw with only `"` re-escaped, so any character that needs an escape, +/// or that the f-string syntax gives meaning to (braces), doesn't round-trip. +fn format_string_fragment_is_representable(string: &str) -> bool { + string.chars().all(|char| char != '\\' && char != '{' && char != '}' && !char.is_control()) +} diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index c2d5aacaed6..7000293891a 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -206,8 +206,20 @@ impl NamedGeneric { pub fn is_associated(&self) -> bool { self.name.contains("::") } + + /// Whether this is the hidden generic desugared from an `impl Trait` parameter + /// (see `desugar_impl_trait_arg`), recognizable by its synthetic name: a user-written + /// generic name can never contain a space. + pub fn is_impl_trait_parameter(&self) -> bool { + self.name.starts_with(IMPL_TRAIT_PARAMETER_NAME_PREFIX) + } } +/// Prefix of the synthetic name minted for the hidden generic that an `impl Trait` parameter +/// desugars to. Shared between the elaborator (which mints the name) and the HIR printer +/// (which recognizes such generics via [`NamedGeneric::is_impl_trait_parameter`]). +pub const IMPL_TRAIT_PARAMETER_NAME_PREFIX: &str = "impl "; + /// A Kind is the type of a Type. These are used since only certain kinds of types are allowed in /// certain positions. /// diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index e3f17fe16da..4dbe100e19c 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -92,7 +92,17 @@ pub fn assert_no_errors_without_report(src: &str) -> Context<'_, '_> { } fn assert_no_errors_and_to_string(src: &str) -> String { - let context = assert_no_errors(src); + assert_no_errors_and_to_string_using_features( + src, + FrontendOptions::test_default().enabled_unstable_features, + ) +} + +fn assert_no_errors_and_to_string_using_features( + src: &str, + features: &[UnstableFeature], +) -> String { + let context = assert_no_errors_using_features(src, features); let expanded = display_crate( *context.crate_graph.root_crate_id(), &context.crate_graph, @@ -107,7 +117,7 @@ fn assert_no_errors_and_to_string(src: &str) -> String { // its module and break access to a module-private item. Only hard errors are checked: the // printer can legitimately produce code whose warnings (e.g. unused imports) differ from the // original. - let errors = get_program_errors(&expanded); + let errors = get_program_using_features(&expanded, features).2; let errors: Vec<_> = errors.iter().map(CustomDiagnostic::from).filter(CustomDiagnostic::is_error).collect(); if !errors.is_empty() { diff --git a/compiler/noirc_frontend/src/tests/expand.rs b/compiler/noirc_frontend/src/tests/expand.rs index 82c70a66167..c6259acd5f6 100644 --- a/compiler/noirc_frontend/src/tests/expand.rs +++ b/compiler/noirc_frontend/src/tests/expand.rs @@ -1,7 +1,7 @@ //! Tests for `nargo expand` output (via the HIR printer), focusing on faithfully //! reconstructing impls: their generics and where clauses. -use crate::tests::assert_no_errors_and_to_string; +use crate::tests::{assert_no_errors_and_to_string, assert_no_errors_and_to_string_using_features}; #[test] fn expands_inherent_impl_with_where_clause() { @@ -562,3 +562,346 @@ fn expands_trait_method_call_shadowed_by_inherent_method() { } "); } + +#[test] +fn expands_self_static_trait_method_call_in_default_method() { + let src = r#" + trait ATrait { + fn static_method() -> Field { + Self::static_method_2() + } + + fn static_method_2() -> Field { + 100 + } + } + + struct Foo {} + + impl ATrait for Foo { + fn static_method_2() -> Field { + 200 + } + } + + fn main() { + let _ = Foo::static_method(); + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + trait ATrait { + fn static_method() -> Field { + Self::static_method_2() + } + + fn static_method_2() -> Field { + 100_Field + } + } + + struct Foo { + } + + impl ATrait for Foo { + fn static_method_2() -> Field { + 200_Field + } + } + + fn main() { + let _: Field = ::static_method(); + } + "); +} + +#[test] +fn expands_impl_trait_parameter_without_where_clause() { + let src = r#" + trait SomeTrait { + fn get_value(self) -> Field; + } + + struct AType {} + + impl SomeTrait for AType { + fn get_value(self) -> Field { + 1 + } + } + + fn take(x: impl SomeTrait) -> Field { + x.get_value() + } + + fn main() { + let _ = take(AType {}); + } + "#; + let expanded = assert_no_errors_and_to_string_using_features( + src, + &[crate::elaborator::UnstableFeature::TraitAsType], + ); + insta::assert_snapshot!(expanded, @r" + trait SomeTrait { + fn get_value(self) -> Field; + } + + struct AType { + } + + impl SomeTrait for AType { + fn get_value(self) -> Field { + 1_Field + } + } + + fn take(x: impl SomeTrait) -> Field { + x.get_value() + } + + fn main() { + let _: Field = take(AType { }); + } + "); +} + +#[test] +fn expands_impl_trait_parameter_with_generics() { + let src = r#" + trait Foo {} + + impl Foo for [Field; N] {} + + fn my_fn(_input: impl Foo) {} + + fn main() { + my_fn::<0>([]); + } + "#; + let expanded = assert_no_errors_and_to_string_using_features( + src, + &[crate::elaborator::UnstableFeature::TraitAsType], + ); + insta::assert_snapshot!(expanded, @r" + trait Foo { + + } + + impl Foo for [Field; N] { + + } + + fn my_fn(_input: impl Foo) { + } + + fn main() { + my_fn::<0>([]); + } + "); +} + +#[test] +fn expands_global_whose_value_has_private_fields_as_its_initializer_expression() { + let src = r#" + mod foo { + pub struct Bar { + value: Field, + } + + pub fn make_bar() -> Bar { + Bar { value: 1 } + } + } + + global B: foo::Bar = foo::make_bar(); + + fn main() { + let _ = B; + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + mod foo { + pub struct Bar { + value: Field, + } + + pub fn make_bar() -> Bar { + Bar { value: 1_Field} + } + } + + global B: foo::Bar = foo::make_bar(); + + fn main() { + let _: foo::Bar = B; + } + "); +} + +#[test] +fn expands_associated_constant_reference_in_impl_method() { + let src = r#" + trait Trait { + let N: u32; + + fn foo() -> u32; + } + + struct Foo {} + + impl Trait for Foo { + let N: u32 = 30; + + fn foo() -> u32 { + Self::N + } + } + + fn main() { + let _ = Foo::foo(); + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + trait Trait { + let N: u32; + + fn foo() -> u32; + } + + struct Foo { + } + + impl Trait for Foo { + let N: u32 = 30_u32; + + fn foo() -> u32 { + Self::N + } + } + + fn main() { + let _: u32 = Foo::foo(); + } + "); +} + +#[test] +fn expands_numeric_type_alias_with_its_numeric_type() { + let src = r#" + type Double: u32 = N * 2; + + fn main() { + let arr: [Field; Double::<2>] = [0; 4]; + let _ = arr; + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + type Double: u32 = N * 2; + + fn main() { + let arr: [Field; 2 * 2] = [0_Field; 4]; + let _: [Field; 2 * 2] = arr; + } + "); +} + +#[test] +fn expands_numeric_type_alias_used_as_value_with_turbofish() { + let src = r#" + type AliasN: u32 = N; + + global N: u32 = 100; + + fn main() { + let a: u32 = AliasN::<1>; + assert(a == 1); + assert(N == 100); + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + type AliasN: u32 = N; + + global N: u32 = 100; + + fn main() { + let a: u32 = 1_u32; + assert(a == 1_u32); + assert(N == 100_u32); + } + "); +} + +#[test] +fn expands_associated_constant_over_self_type_with_concrete_annotation() { + let src = r#" + trait Foo { + let N: i32; + + fn n() -> i32 { + Self::N + } + } + + impl Foo for i32 { + let N: i32 = -12345i32; + } + + fn main() { + let _ = i32::n(); + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + trait Foo { + let N: i32; + + fn n() -> i32 { + Self::N + } + } + + impl Foo for i32 { + let N: i32 = -12345_i32; + } + + fn main() { + let _: i32 = ::n(); + } + "); +} + +#[test] +fn expands_global_capturing_closure_as_its_initializer_expression() { + let src = r#" + fn make() -> fn[(Field,)](Field) -> Field { + let x: Field = 3; + |y: Field| -> Field { y + x } + } + + global F: fn[(Field,)](Field) -> Field = make(); + + fn main() { + let _ = F; + } + "#; + let expanded = assert_no_errors_and_to_string(src); + insta::assert_snapshot!(expanded, @r" + fn make() -> fn[(Field,)](Field) -> Field { + let x: Field = 3_Field; + |y: Field| -> Field { + y + x + } + } + + global F: fn[(Field,)](Field) -> Field = make(); + + fn main() { + let _: fn[(Field,)](Field) -> Field = F; + } + "); +} diff --git a/test_programs/execution_success/comptime_mutated_global/Nargo.toml b/test_programs/execution_success/comptime_mutated_global/Nargo.toml new file mode 100644 index 00000000000..7f493f7310a --- /dev/null +++ b/test_programs/execution_success/comptime_mutated_global/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "comptime_mutated_global" +type = "bin" +authors = [""] +[dependencies] diff --git a/test_programs/execution_success/comptime_mutated_global/Prover.toml b/test_programs/execution_success/comptime_mutated_global/Prover.toml new file mode 100644 index 00000000000..0e5dfd5638d --- /dev/null +++ b/test_programs/execution_success/comptime_mutated_global/Prover.toml @@ -0,0 +1 @@ +x = "5" diff --git a/test_programs/execution_success/comptime_mutated_global/src/main.nr b/test_programs/execution_success/comptime_mutated_global/src/main.nr new file mode 100644 index 00000000000..5f91840da39 --- /dev/null +++ b/test_programs/execution_success/comptime_mutated_global/src/main.nr @@ -0,0 +1,18 @@ +// A comptime-mutable global observed at runtime must expand to its final mutated value, +// not its initializer: the attribute that mutates it is already expanded away, so +// re-evaluating the initializer would produce a different program. +comptime mut global COUNTER: u32 = 0; + +comptime fn bump(_f: FunctionDefinition) { + COUNTER += 1; +} + +#[bump] +fn foo() {} + +fn main(x: Field) { + foo(); + let counter = comptime { COUNTER }; + assert(counter == 1); + assert(x == 5); +} diff --git a/test_programs/execution_success/global_string_control_char/Nargo.toml b/test_programs/execution_success/global_string_control_char/Nargo.toml new file mode 100644 index 00000000000..dfa1027f18e --- /dev/null +++ b/test_programs/execution_success/global_string_control_char/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "global_string_control_char" +type = "bin" +authors = [""] +[dependencies] diff --git a/test_programs/execution_success/global_string_control_char/Prover.toml b/test_programs/execution_success/global_string_control_char/Prover.toml new file mode 100644 index 00000000000..0e5dfd5638d --- /dev/null +++ b/test_programs/execution_success/global_string_control_char/Prover.toml @@ -0,0 +1 @@ +x = "5" diff --git a/test_programs/execution_success/global_string_control_char/src/main.nr b/test_programs/execution_success/global_string_control_char/src/main.nr new file mode 100644 index 00000000000..c259018e9d3 --- /dev/null +++ b/test_programs/execution_success/global_string_control_char/src/main.nr @@ -0,0 +1,11 @@ +// A string global containing a control character is valid UTF-8 but can't be printed as a +// Noir string literal (Rust's `{:?}` escapes it as `\u{..}`, which Noir doesn't lex), so +// `nargo expand` must print the initializer expression instead of the value. +global BYTES: [u8; 4] = [102, 7, 111, 111]; +global S: str<4> = BYTES.as_str_unchecked(); + +fn main(x: Field) { + let bytes = S.as_bytes(); + assert(bytes[1] as Field + x == 12); + assert(x == 5); +} diff --git a/test_programs/execution_success/numeric_type_alias_inference/Nargo.toml b/test_programs/execution_success/numeric_type_alias_inference/Nargo.toml new file mode 100644 index 00000000000..2586ed9caeb --- /dev/null +++ b/test_programs/execution_success/numeric_type_alias_inference/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "numeric_type_alias_inference" +type = "bin" +authors = [""] +[dependencies] diff --git a/test_programs/execution_success/numeric_type_alias_inference/Prover.toml b/test_programs/execution_success/numeric_type_alias_inference/Prover.toml new file mode 100644 index 00000000000..0e5dfd5638d --- /dev/null +++ b/test_programs/execution_success/numeric_type_alias_inference/Prover.toml @@ -0,0 +1 @@ +x = "5" diff --git a/test_programs/execution_success/numeric_type_alias_inference/src/main.nr b/test_programs/execution_success/numeric_type_alias_inference/src/main.nr new file mode 100644 index 00000000000..e46e8e7fa03 --- /dev/null +++ b/test_programs/execution_success/numeric_type_alias_inference/src/main.nr @@ -0,0 +1,32 @@ +// A numeric type alias's parameter used as a value must keep its numeric type through +// `nargo expand` (which prints it as a constant): if the constant loses its `u8` type, +// inference picks `impl Which for Field` instead and `which` returns the wrong value. +trait Which { + fn which(self) -> Field; +} + +impl Which for u8 { + fn which(self) -> Field { + 1 + } +} + +impl Which for Field { + fn which(self) -> Field { + 2 + } +} + +type AliasN: u8 = N; + +fn takes(value: T) -> T +where + T: Which, +{ + value +} + +fn main(x: Field) { + assert(takes(AliasN::<200_u8>).which() == 1); + assert(x == 5); +} diff --git a/tooling/nargo_cli/build.rs b/tooling/nargo_cli/build.rs index 9fb8dedde38..698f5cc3ce8 100644 --- a/tooling/nargo_cli/build.rs +++ b/tooling/nargo_cli/build.rs @@ -214,30 +214,14 @@ const IGNORED_MINIMAL_EXECUTION_TESTS: [&str; 18] = [ /// These tests are ignored because making them work involves a more complex test code that /// might not be worth it. -/// Others are ignored because of existing bugs in `nargo expand`. -/// As the bugs are fixed these tests should be removed from this list. -const IGNORED_NARGO_EXPAND_EXECUTION_TESTS: [&str; 12] = [ - // `nargo expand` prints an associated-constant access by its bare name (e.g. `N`), - // dropping the `Box::::` qualifier, so the expanded source no longer resolves. - "comptime_resolve_associated_constant_scope", +const IGNORED_NARGO_EXPAND_EXECUTION_TESTS: [&str; 5] = [ // There's nothing special about this program but making it work with a custom entry would involve // having to parse the Nargo.toml file, etc., which is not worth it "custom_entry", // There's no "src/main.nr" here so it's trickier to make this work "diamond_deps_0", - // bug - "numeric_type_alias", - "negative_associated_constants", // There's no "src/main.nr" here so it's trickier to make this work "overlapping_dep_and_mod", - // bug - "regression_9116", - // bug - "regression_10466", - // bug - "trait_associated_constant", - // Globals evaluate to invalid utf-8 which don't display correctly in a source file - "regression_12269", // There's no "src/main.nr" here so it's trickier to make this work "workspace", // There's no "src/main.nr" here so it's trickier to make this work @@ -247,30 +231,17 @@ const IGNORED_NARGO_EXPAND_EXECUTION_TESTS: [&str; 12] = [ /// Tests for which we don't check that stdout matches the expected output. const TESTS_WITHOUT_STDOUT_CHECK: [&str; 0] = []; -/// These tests are ignored because of existing bugs in `nargo expand`. -/// As the bugs are fixed these tests should be removed from this list. -/// (some are ignored on purpose for the same reason as `IGNORED_NARGO_EXPAND_EXECUTION_TESTS`) -const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_EMPTY_TESTS: [&str; 11] = [ - // A generated associated constant resolves to `<[T; N] as Ser>::N`, which `nargo expand` - // prints as `<(resolved type) as Ser>::N` — not valid syntax to recompile. - "regression_10747_associated_constant", +/// These tests are ignored on purpose for the same reason as +/// `IGNORED_NARGO_EXPAND_EXECUTION_TESTS`: making them work involves more complex test code +/// that might not be worth it. +const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_EMPTY_TESTS: [&str; 5] = [ // There's no "src/main.nr" here so it's trickier to make this work "overlapping_dep_and_mod", // this one works, but copying its `Nargo.toml` file to somewhere else doesn't work // because it references another project by a relative path "reexports", - // bug - "trait_function_calls", - // bug - "trait_method_mut_self", - // bug - "trait_static_methods", // There's no "src/main.nr" here so it's trickier to make this work "workspace_reexport_bug", - // bug - "trait_call_in_global", - // `nargo expand` drops the trait generic arguments on `impl Trait<...>` parameters - "regression_7648", // The expanded code names a transitive-only dependency (`leaflib`) by path, which isn't // directly importable when the expansion is recompiled as a standalone program. "comptime_as_typed_expr_public_type_trait_method", @@ -281,26 +252,7 @@ const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_EMPTY_TESTS: [&str; 11] = [ /// These tests are ignored because of existing bugs in `nargo expand`. /// As the bugs are fixed these tests should be removed from this list. -const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_NO_BUG_TESTS: [&str; 17] = [ - "noirc_frontend_tests_check_trait_as_type_as_fn_parameter", - "noirc_frontend_tests_check_trait_as_type_as_two_fn_parameters", - "noirc_frontend_tests_enums_match_on_empty_enum", - "noirc_frontend_tests_traits_trait_alias_polymorphic_inheritance", - "noirc_frontend_tests_traits_trait_alias_single_member", - "noirc_frontend_tests_traits_trait_alias_two_members", - "noirc_frontend_tests_traits_trait_impl_with_where_clause_with_trait_with_associated_numeric", - "noirc_frontend_tests_traits_accesses_associated_type_inside_trait_impl_using_self", - "noirc_frontend_tests_traits_accesses_associated_type_inside_trait_using_self", - "noirc_frontend_tests_u32_globals_as_sizes_in_types", - // This creates a struct at comptime which, expanded, gives a visibility error - "noirc_frontend_tests_visibility_visibility_bug_inside_comptime", - "noirc_frontend_tests_aliases_identity_numeric_type_alias_works", - "noirc_frontend_tests_aliases_type_alias_to_numeric_as_generic", - "noirc_frontend_tests_aliases_type_alias_to_numeric_generic", - "noirc_frontend_tests_traits_trait_bound_on_implementing_type", - "function_registry", - "regression_10887", // expands into global struct with private fields -]; +const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_NO_BUG_TESTS: [&str; 0] = []; const IGNORED_NARGO_EXPAND_COMPILE_SUCCESS_WITH_BUG_TESTS: [&str; 0] = []; diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/as_trait_path_type_expression/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/as_trait_path_type_expression/execute__tests__expanded.snap index a289f2edd41..e3e60148875 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/as_trait_path_type_expression/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/as_trait_path_type_expression/execute__tests__expanded.snap @@ -9,7 +9,7 @@ trait Trait { } impl Trait for Field { - let N: u32 = 10; + let N: u32 = 10_u32; } fn main() { diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/associated_constants_in_as_trait_expr/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/associated_constants_in_as_trait_expr/execute__tests__expanded.snap index 45f97f35aab..a53e2abbba8 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/associated_constants_in_as_trait_expr/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/associated_constants_in_as_trait_expr/execute__tests__expanded.snap @@ -7,7 +7,7 @@ trait Serialize { } impl Serialize for Field { - let N: u32 = 1; + let N: u32 = 1_u32; } fn main() { diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_trait_associated_type_regression_8252/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_trait_associated_type_regression_8252/execute__tests__expanded.snap index 217d01686ee..f079e9129ce 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_trait_associated_type_regression_8252/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/nested_trait_associated_type_regression_8252/execute__tests__expanded.snap @@ -13,13 +13,13 @@ trait TraitWithAssociatedConstant { struct Foo {} impl TraitWithAssociatedConstant for Foo { - let N: u32 = 42; + let N: u32 = 42_u32; } struct Bar {} impl TraitWithAssociatedConstant for Bar { - let N: u32 = 43; + let N: u32 = 43_u32; } struct Wrapper { diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10747_associated_constant/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10747_associated_constant/execute__tests__expanded.snap index bdc6c87346b..567e35b9532 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10747_associated_constant/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10747_associated_constant/execute__tests__expanded.snap @@ -2,16 +2,18 @@ source: tooling/nargo_cli/tests/execute.rs expression: expanded_code --- - pub trait Ser { let N: u32; } impl Ser for Field { - let N: u32 = 1; + let N: u32 = 1_u32; } -impl Ser for [T; M] where T: Ser { +impl Ser for [T; M] +where + T: Ser, +{ let N: u32 = M * ::N; } @@ -19,22 +21,37 @@ struct Wrapped { xs: [T; N], } -impl Ser for Wrapped where T: Ser { - let N: u32 = N * <(resolved type) as Ser>::N; +impl Ser for Wrapped +where + T: Ser, +{ + let N: u32 = N * ::N; } pub comptime fn derive_ser(s: TypeDefinition) -> Quoted { let typ: Type = s.as_type(); - let rhs: Quoted = s.fields_as_written().map(|(_, field_type, _): (Quoted, Type, Quoted)| -> Quoted quote { < $field_type as Ser > ::N }).join(quote { + }); - let generics: Quoted = s.generics().map(|(name, maybe_int): (Type, Option)| -> Quoted { - if maybe_int.is_some() { - let int_type: Type = maybe_int.unwrap(); - quote { let $name: $int_type } - } else { - quote { $name } - } - }).join(quote { , }); - let where_clause: Quoted = s.generics().filter(|(_, maybe_int): (Type, Option)| -> bool maybe_int.is_none()).map(|(name, _): (Type, Option)| -> Quoted quote { $name: Ser }).join(quote { , }); + let rhs: Quoted = s + .fields_as_written() + .map(|(_, field_type, _): (Quoted, Type, Quoted)| -> Quoted { + quote { <$field_type as Ser>::N } + }) + .join(quote { + }); + let generics: Quoted = s + .generics() + .map(|(name, maybe_int): (Type, Option)| -> Quoted { + if maybe_int.is_some() { + let int_type: Type = maybe_int.unwrap(); + quote { let $name: $int_type } + } else { + quote { $name } + } + }) + .join(quote { , }); + let where_clause: Quoted = s + .generics() + .filter(|(_, maybe_int): (Type, Option)| -> bool maybe_int.is_none()) + .map(|(name, _): (Type, Option)| -> Quoted quote { $name: Ser }) + .join(quote { , }); quote { impl < $generics > Ser for $typ where $where_clause { let N: u32 = $rhs; @@ -43,8 +60,6 @@ pub comptime fn derive_ser(s: TypeDefinition) -> Quoted { } fn main() { - let _wrapped: Wrapped = Wrapped:: { xs: [1_Field, 2_Field, 3_Field]}; + let _wrapped: Wrapped = Wrapped:: { xs: [1_Field, 2_Field, 3_Field] }; let _len: u32 = as Ser>::N; } - -// Warning: the generated code has syntax errors diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10813/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10813/execute__tests__expanded.snap index e92992f6114..aba6c97e16b 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10813/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_10813/execute__tests__expanded.snap @@ -13,7 +13,7 @@ pub trait Foo { } impl Foo for () { - let Baz: u32 = 0; + let Baz: u32 = 0_u32; type Bar = Self; } diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_12659_associated_constant_projection_in_struct_field/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_12659_associated_constant_projection_in_struct_field/execute__tests__expanded.snap index c8c7bf4389b..e6a2a49aca5 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_12659_associated_constant_projection_in_struct_field/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_12659_associated_constant_projection_in_struct_field/execute__tests__expanded.snap @@ -9,7 +9,7 @@ pub trait HasSize { pub struct PublicMutable {} impl HasSize for PublicMutable { - let N: u32 = 1; + let N: u32 = 1_u32; } pub struct Wrapper { diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_7648/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_7648/execute__tests__expanded.snap index 5ac81de9765..510a2be0f8d 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_7648/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_7648/execute__tests__expanded.snap @@ -6,10 +6,7 @@ trait Foo {} impl Foo for [Field; N] {} -fn my_fn(_input: impl Foo) -where - impl Foo: Foo, -{} +fn my_fn(_input: impl Foo) {} fn main() { my_fn::<0>([]); diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9245/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9245/execute__tests__expanded.snap index 600ed964bac..4b973a0ee13 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9245/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9245/execute__tests__expanded.snap @@ -9,7 +9,7 @@ pub trait Deserialize { } impl Deserialize for Field { - let N: u32 = 1; + let N: u32 = 1_u32; fn deserialize(fields: [Self; 1]) -> Self { fields[0_u32] diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9248/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9248/execute__tests__expanded.snap index beb2d3b55b6..789173efc90 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9248/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/regression_9248/execute__tests__expanded.snap @@ -9,7 +9,7 @@ pub trait Deserialize { } impl Deserialize for Field { - let N: u32 = 1; + let N: u32 = 1_u32; fn deserialize(fields: [Self; 1]) -> Self { fields[0_u32] diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_1/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_1/execute__tests__expanded.snap index 3328d1e1f05..8c8dc2c814a 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_1/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_1/execute__tests__expanded.snap @@ -60,7 +60,7 @@ where } impl Serialize for Field { - let Size: u32 = 1; + let Size: u32 = 1_u32; fn serialize(self) -> [Self; 1] { [self] diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_2/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_2/execute__tests__expanded.snap index 163de61e9fd..05b74171081 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_2/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_2/execute__tests__expanded.snap @@ -9,7 +9,7 @@ trait Serialize { } impl Serialize for Field { - let Size: u32 = 1; + let Size: u32 = 1_u32; fn serialize(self) {} } diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_3/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_3/execute__tests__expanded.snap index a92f6580693..4aedb792cd3 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_3/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_3/execute__tests__expanded.snap @@ -33,7 +33,7 @@ where } impl Serialize for Field { - let Size: u32 = 1; + let Size: u32 = 1_u32; fn serialize(self) -> [Self; 1] { [self] diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_4/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_4/execute__tests__expanded.snap index c1df8155f22..2c4eb0a9a3b 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_4/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_4/execute__tests__expanded.snap @@ -60,7 +60,7 @@ where } impl Serialize for Field { - let Size: u32 = 1; + let Size: u32 = 1_u32; fn serialize(self) -> [Self; 1] { [self] diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_5/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_5/execute__tests__expanded.snap index 3d7f71c7d04..7698d9ca6d1 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_5/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/serialize_5/execute__tests__expanded.snap @@ -9,7 +9,7 @@ trait Serialize { } impl Serialize for Field { - let N: u32 = 1; + let N: u32 = 1_u32; fn serialize(self) -> [Self; 1] { [self] @@ -21,7 +21,7 @@ pub struct Foo { } impl Serialize for Foo { - let N: u32 = 1; + let N: u32 = 1_u32; fn serialize(self) -> [Field; 1] { [0_Field; 1] @@ -31,7 +31,7 @@ impl Serialize for Foo { pub struct Bar {} impl Serialize for Bar { - let N: u32 = 1; + let N: u32 = 1_u32; fn serialize(self) -> [Field; 1] { [1_Field] @@ -43,7 +43,7 @@ pub struct Baz { } impl Serialize for Baz { - let N: u32 = 1; + let N: u32 = 1_u32; fn serialize(self) -> [Field; 1] { [0_Field; 1] diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_call_in_global/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_call_in_global/execute__tests__expanded.snap index f14a99900b7..7d83623a47d 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_call_in_global/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_call_in_global/execute__tests__expanded.snap @@ -2,7 +2,7 @@ source: tooling/nargo_cli/tests/execute.rs expression: expanded_code --- -global s: BoundedVec = BoundedVec:: { len: 1, storage: [0x00, 0x00] }; +global s: BoundedVec = as From<[Field; 1]>>::from([0_Field]); fn main() { let _: BoundedVec = s; diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_function_calls/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_function_calls/execute__tests__expanded.snap index 777a0beb4b6..b6d7107e7f2 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_function_calls/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_function_calls/execute__tests__expanded.snap @@ -232,7 +232,7 @@ impl Trait1i for Struct1i { trait Trait2a { fn trait_method1(self) -> Field { - (Trait2a::trait_function2() * 2385_Field) - self.vl() + (Self::trait_function2() * 2385_Field) - self.vl() } fn trait_function2() -> Field { @@ -254,7 +254,7 @@ impl Trait2a for Struct2a { trait Trait2b { fn trait_method1(self) -> Field { - (Trait2b::trait_function2() * 6583_Field) - self.vl() + (Self::trait_function2() * 6583_Field) - self.vl() } fn trait_function2() -> Field { @@ -280,7 +280,7 @@ impl Trait2b for Struct2b { trait Trait2c { fn trait_method1(self) -> Field { - (Trait2c::trait_function2() * 2831_Field) - self.vl() + (Self::trait_function2() * 2831_Field) - self.vl() } fn trait_function2() -> Field; @@ -304,7 +304,7 @@ impl Trait2c for Struct2c { trait Trait2d { fn trait_method1(self) -> Field { - (Trait2d::trait_function2() * 924_Field) - self.vl() + (Self::trait_function2() * 924_Field) - self.vl() } fn trait_function2() -> Field { @@ -330,7 +330,7 @@ impl Trait2d for Struct2d { trait Trait2e { fn trait_method1(self) -> Field { - (Trait2e::trait_function2() * 3642_Field) - self.vl() + (Self::trait_function2() * 3642_Field) - self.vl() } fn trait_function2() -> Field { @@ -360,7 +360,7 @@ impl Trait2e for Struct2e { trait Trait2f { fn trait_method1(self) -> Field { - (Trait2f::trait_function2() * 2783_Field) - self.vl() + (Self::trait_function2() * 2783_Field) - self.vl() } fn trait_function2() -> Field; @@ -676,7 +676,7 @@ impl Trait3i for Struct3i { trait Trait4a { fn trait_function1() -> Field { - Trait4a::trait_function2() * 3842_Field + Self::trait_function2() * 3842_Field } fn trait_function2() -> Field { @@ -692,7 +692,7 @@ impl Trait4a for Struct4a {} trait Trait4b { fn trait_function1() -> Field { - Trait4b::trait_function2() * 3842_Field + Self::trait_function2() * 3842_Field } fn trait_function2() -> Field { @@ -712,7 +712,7 @@ impl Trait4b for Struct4b { trait Trait4c { fn trait_function1() -> Field { - Trait4c::trait_function2() * 7832_Field + Self::trait_function2() * 7832_Field } fn trait_function2() -> Field; @@ -730,7 +730,7 @@ impl Trait4c for Struct4c { trait Trait4d { fn trait_function1() -> Field { - Trait4d::trait_function2() * 2283_Field + Self::trait_function2() * 2283_Field } fn trait_function2() -> Field { @@ -750,7 +750,7 @@ impl Trait4d for Struct4d { trait Trait4e { fn trait_function1() -> Field { - Trait4e::trait_function2() * 94329_Field + Self::trait_function2() * 94329_Field } fn trait_function2() -> Field { @@ -774,7 +774,7 @@ impl Trait4e for Struct4e { trait Trait4f { fn trait_function1() -> Field { - Trait4f::trait_function2() * 23723_Field + Self::trait_function2() * 23723_Field } fn trait_function2() -> Field; diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_inheritence_call_method_on_self/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_inheritence_call_method_on_self/execute__tests__expanded.snap index ff9c80c304f..10044390e28 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_inheritence_call_method_on_self/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_inheritence_call_method_on_self/execute__tests__expanded.snap @@ -6,7 +6,7 @@ pub trait Empty: Eq { fn empty() -> Self; fn is_empty(self) -> bool { - self.eq(Empty::empty()) + self.eq(Self::empty()) } } diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_method_mut_self/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_method_mut_self/execute__tests__expanded.snap index 51c533df91f..fcbd2e84d49 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_method_mut_self/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_method_mut_self/execute__tests__expanded.snap @@ -40,10 +40,7 @@ impl SomeTrait for AType { } } -fn pass_trait_by_value_impl_param(mut a_mut_ref: impl SomeTrait, value: Field) -where - impl SomeTrait: SomeTrait, -{ +fn pass_trait_by_value_impl_param(mut a_mut_ref: impl SomeTrait, value: Field) { a_mut_ref.set_value(value); assert(a_mut_ref.get_value() == value); } diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_static_methods/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_static_methods/execute__tests__expanded.snap index 60bb0c53941..bcbdcac2662 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_static_methods/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_empty/trait_static_methods/execute__tests__expanded.snap @@ -6,7 +6,7 @@ trait ATrait { fn asd() -> Self; fn static_method() -> Field { - ATrait::static_method_2() + Self::static_method_2() } fn static_method_2() -> Field { diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/function_registry/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/function_registry/execute__tests__expanded.snap index 0d25b7b83d2..2f67392c513 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/function_registry/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/function_registry/execute__tests__expanded.snap @@ -4,24 +4,8 @@ expression: expanded_code --- use std::{collections::umap::UHashMap, hash::{BuildHasherDefault, Hasher}}; -comptime mut global REGISTRY: UHashMap> = UHashMap::> { - _len: 1, - _table: @[ - std::collections::umap::Slot:: { - _value: @[panic(f"comptime value that cannot be represented with code")], - _is_present: true, - _key: panic(f"comptime value that cannot be represented with code"), - _is_deleted: false, - }, - std::collections::umap::Slot:: { - _value: @[], - _is_present: false, - _key: crate::mem::zeroed(), - _is_deleted: false, - }, - ], - _build_hasher: BuildHasherDefault:: {}, -}; +comptime mut global REGISTRY: UHashMap> = + UHashMap::>::default(); // Warning: this global was mutated at compile time; its final value could not be printed, so this is its initializer comptime fn add_to_registry( registry: &mut UHashMap>, diff --git a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/regression_10887/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/regression_10887/execute__tests__expanded.snap index e9e17d90290..f7850807339 100644 --- a/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/regression_10887/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/compile_success_no_bug/regression_10887/execute__tests__expanded.snap @@ -2,7 +2,7 @@ source: tooling/nargo_cli/tests/execute.rs expression: expanded_code --- -global G_A: Option = Option:: { _is_some: false, _value: false }; +global G_A: Option = Option::::none(); fn main() { let a: Option = Option::::none(); diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/associated_constant_as_array_length/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/associated_constant_as_array_length/execute__tests__expanded.snap index 7beb393e16c..14fa0e15ae7 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/associated_constant_as_array_length/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/associated_constant_as_array_length/execute__tests__expanded.snap @@ -9,7 +9,7 @@ trait HasSize { struct Packet {} impl HasSize for Packet { - let SIZE: u32 = 4; + let SIZE: u32 = 4_u32; } global N: u32 = 4; diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/comptime_mutated_global/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/comptime_mutated_global/execute__tests__expanded.snap new file mode 100644 index 00000000000..ad752270043 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/comptime_mutated_global/execute__tests__expanded.snap @@ -0,0 +1,18 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +comptime mut global COUNTER: u32 = 1; + +comptime fn bump(_f: FunctionDefinition) { + COUNTER = COUNTER + 1_u32; +} + +fn foo() {} + +fn main(x: Field) { + foo(); + let counter: u32 = 1_u32; + assert(counter == 1_u32); + assert(x == 5_Field); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/comptime_mutated_global/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/comptime_mutated_global/execute__tests__stdout.snap new file mode 100644 index 00000000000..e86e3de90e1 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/comptime_mutated_global/execute__tests__stdout.snap @@ -0,0 +1,5 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- + diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/comptime_resolve_associated_constant_scope/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/comptime_resolve_associated_constant_scope/execute__tests__expanded.snap new file mode 100644 index 00000000000..964d80b8bcb --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/comptime_resolve_associated_constant_scope/execute__tests__expanded.snap @@ -0,0 +1,32 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +mod victim { + pub struct Box { + pub value: T, + } + + impl LocalConst for Box { + let N: u32 = 1_u32; + } + + impl crate::CallerConst for Box { + let N: u32 = 2_u32; + } + + trait LocalConst { + let N: u32; + } + + pub fn scope_anchor() {} +} + +trait CallerConst { + let N: u32; +} + +fn main() { + let selected: u32 = { 1_u32 }; + assert(selected == 1_u32); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/global_string_control_char/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/global_string_control_char/execute__tests__expanded.snap new file mode 100644 index 00000000000..62dfd23fe35 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/global_string_control_char/execute__tests__expanded.snap @@ -0,0 +1,13 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +global BYTES: [u8; 4] = [102, 7, 111, 111]; + +global S: str<4> = BYTES.as_str_unchecked(); + +fn main(x: Field) { + let bytes: [u8; 4] = S.as_bytes(); + assert(((bytes[1_u32] as Field) + x) == 12_Field); + assert(x == 5_Field); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/global_string_control_char/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/global_string_control_char/execute__tests__stdout.snap new file mode 100644 index 00000000000..e86e3de90e1 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/global_string_control_char/execute__tests__stdout.snap @@ -0,0 +1,5 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- + diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/negative_associated_constants/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/negative_associated_constants/execute__tests__expanded.snap new file mode 100644 index 00000000000..96a467a4dc4 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/negative_associated_constants/execute__tests__expanded.snap @@ -0,0 +1,28 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +trait Foo { + let N: i32; + + let M: i32; + + fn n() -> i32 { + Self::N + } + + fn m() -> i32 { + Self::M + } +} + +impl Foo for i32 { + let N: i32 = -12345_i32; + + let M: i32 = -7655_i32; +} + +fn main() { + println(::n()); + println(::m()); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias/execute__tests__expanded.snap new file mode 100644 index 00000000000..c69bca1f60c --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias/execute__tests__expanded.snap @@ -0,0 +1,117 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +type Double: u32 = N * 2; + +type Quadruple: u32 = (N * 2) + (N * 2); + +type Mixed: u32 = N * ((N * 2) + 3); + +global One: u32 = 1; + +type Two: u32 = 2; + +type Three: u32 = 3; + +global N: u32 = 100; + +type AliasN: u32 = N; + +fn main(x: Field) { + let arr: [Field; (2 * 2) + (2 * 2)] = [0_Field; 8]; + assert(arr.len() == 8_u32); + let b: [u32; 12] = quadruple_array::<3>(); + assert(b[0_u32] == 0_u32); + let c: [u32; 14] = mixed_array::<2>(); + assert(c[0_u32] == 0_u32); + let two: u32 = One + One; + assert(two == 2_u32); + let three: u32 = (One + One) + One; + assert(three == 3_u32); + let arr2: [Field; 2] = [0_Field; 2]; + assert(arr2.len() == 2_u32); + let a: u32 = 1_u32; + assert(a == 1_u32); + assert(N == 100_u32); + let b: u32 = 5_u32; + assert(b == 5_u32); + let mut m: Matrix<3, 4> = new_matrix::<3, 4>(); + m.elements[(3_u32 * 2_u32) + 3_u32] = 10_Field; + m.elements[(3_u32 * 2_u32) + (x as u32)] = 5_Field + x; + assert(equal(m, m)); + let b: Matrix<4, 3> = transpose(m); + assert(b.elements != m.elements); + assert(trace(b) != trace(m)); + assert(sum(b) == sum(m)); + let a: BoundedVec = test_2::<4>(x); + assert(a.len() == 1_u32); +} + +fn quadruple_array() -> [u32; (N * 2) + (N * 2)] { + let mut a: [u32; (N * 2) + (N * 2)] = [0_u32; (N * 2) + (N * 2)]; + for i in 0_u32..(N * 2_u32) + (N * 2_u32) { + a[i] = i; + } + a +} + +fn mixed_array() -> [u32; N * ((N * 2) + 3)] { + let mut a: [u32; N * ((N * 2) + 3)] = [0_u32; N * ((N * 2) + 3)]; + for i in 0_u32..N * ((N * 2_u32) + 3_u32) { + a[i] = i; + } + a +} + +fn test_2(x: Field) -> BoundedVec> { + let mut a: BoundedVec = BoundedVec::::new(); + a.push(x); + a +} + +type MSize: u32 = N * M; + +struct Matrix { + elements: [Field; N * M], +} + +fn new_matrix() -> Matrix { + let mut a: [Field; N * M] = [0_Field; N * M]; + Matrix:: { elements: a } +} + +fn trace(A: Matrix) -> Field { + let n: u32 = if N > M { M } else { N }; + let mut s: Field = 0_Field; + for i in 0_u32..n { + s = s + A.elements[(i * N) + i]; + } + s +} + +fn sum(A: Matrix) -> Field { + let mut s: Field = 0_Field; + for i in 0_u32..N * M { + s = s + A.elements[i]; + } + s +} + +fn equal(A: Matrix, B: Matrix) -> bool { + let mut s: bool = true; + for i in 0_u32..N * M { + s = s | (A.elements[i] == B.elements[i]); + } + s +} + +fn transpose(a: Matrix) -> Matrix { + let mut b: Matrix = new_matrix::(); + for i in 0_u32..N { + for j in 0_u32..M { + b.elements[(j * N) + i] = a.elements[(i * M) + j]; + } + } + b +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias_inference/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias_inference/execute__tests__expanded.snap new file mode 100644 index 00000000000..46d3e04b7cd --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias_inference/execute__tests__expanded.snap @@ -0,0 +1,33 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +trait Which { + fn which(self) -> Field; +} + +impl Which for u8 { + fn which(self) -> Field { + 1_Field + } +} + +impl Which for Field { + fn which(self) -> Self { + 2_Field + } +} + +type AliasN: u8 = N; + +fn takes(value: T) -> T +where + T: Which, +{ + value +} + +fn main(x: Field) { + assert(takes(200_u8).which() == 1_Field); + assert(x == 5_Field); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias_inference/execute__tests__stdout.snap b/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias_inference/execute__tests__stdout.snap new file mode 100644 index 00000000000..e86e3de90e1 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/numeric_type_alias_inference/execute__tests__stdout.snap @@ -0,0 +1,5 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stdout +--- + diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_10466/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10466/execute__tests__expanded.snap new file mode 100644 index 00000000000..3a939cf77ab --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_10466/execute__tests__expanded.snap @@ -0,0 +1,34 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +pub trait Serialize { + let N: u32; + + fn serialize(self); +} + +impl Serialize for Field { + let N: u32 = 1_u32; + + fn serialize(self) {} +} + +impl Serialize for [T; M] +where + T: Serialize, +{ + let N: u32 = M * ::N; + + fn serialize(self) { + println(Self::N); + println(T::N); + println(M); + assert((T::N * M) == Self::N); + } +} + +fn main() { + let nested_array: [[Field; 1]; 2] = [[1_Field], [2_Field]]; + let _: () = nested_array.serialize(); +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_12269/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_12269/execute__tests__expanded.snap index 9cd4c7020d5..755c5a3216e 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/regression_12269/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_12269/execute__tests__expanded.snap @@ -4,7 +4,7 @@ expression: expanded_code --- global BROKEN_BYTES: [u8; 4] = [102, 111, 128, 111]; -global S: str<4> = "fo�o"; +global S: str<4> = BROKEN_BYTES.as_str_unchecked(); fn main() { println(S); diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_8210/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_8210/execute__tests__expanded.snap index 67b9143a76a..918ce6d6730 100644 --- a/tooling/nargo_cli/tests/snapshots/execution_success/regression_8210/execute__tests__expanded.snap +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_8210/execute__tests__expanded.snap @@ -6,24 +6,24 @@ trait Foo { let BAR: u32; fn via_trait(_: Self) -> u32 { - BAR + Self::BAR } fn via_self(_: Self) -> u32 { - BAR + Self::BAR } fn arith(_: Self) -> u32 { - BAR + 1_u32 + Self::BAR + 1_u32 } } impl Foo for Field { - let BAR: u32 = 254; + let BAR: u32 = 254_u32; } impl Foo for u8 { - let BAR: u32 = 7; + let BAR: u32 = 7_u32; } struct Wrapper { @@ -31,7 +31,7 @@ struct Wrapper { } impl Foo for Wrapper { - let BAR: u32 = 11; + let BAR: u32 = 11_u32; } fn main() { diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/regression_9116/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/regression_9116/execute__tests__expanded.snap new file mode 100644 index 00000000000..b9f6ea4181f --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/regression_9116/execute__tests__expanded.snap @@ -0,0 +1,195 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +use meta::{derive_deserialize, derive_serialize}; + +trait Serialize { + let N: u32; + + fn serialize(self) -> [Field; N]; +} + +impl Serialize for Field { + let N: u32 = 1_u32; + + #[inline_always] + fn serialize(self) -> [Self; 1] { + [self] + } +} + +impl Serialize for [Field; M] { + let N: u32 = M; + + #[inline_always] + fn serialize(self) -> Self { + self + } +} + +trait Deserialize { + let N: u32; + + fn deserialize(fields: [Field; N]) -> Self; +} + +impl Deserialize for Field { + let N: u32 = 1_u32; + + #[inline_always] + fn deserialize(fields: [Self; 1]) -> Self { + fields[0_u32] + } +} + +impl Deserialize for [Field; M] { + let N: u32 = M; + + #[inline_always] + fn deserialize(fields: Self) -> Self { + fields + } +} + +struct Foo { + x: Field, + y: [Field; 3], +} + +impl Eq for Foo { + fn eq(_self: Self, _other: Self) -> bool { + (_self.x == _other.x) & (_self.y == _other.y) + } +} + +impl Serialize for Foo { + let N: u32 = 4; + + #[inline_always] + fn serialize(self) -> [Field; 4] { + let mut result: [Field; 4] = [0_Field; 4]; + let mut offset: u32 = 0_u32; + let serialized_member: [Field; 1] = self.x.serialize(); + let serialized_member_len: u32 = ::N; + for i in 0_u32..serialized_member_len { + result[i + offset] = serialized_member[i]; + } + offset = offset + serialized_member_len; + let serialized_member: [Field; 3] = self.y.serialize(); + let serialized_member_len: u32 = <[Field; 3] as Serialize>::N; + for i in 0_u32..serialized_member_len { + result[i + offset] = serialized_member[i]; + } + offset = offset + serialized_member_len; + result + } +} + +impl Deserialize for Foo { + let N: u32 = 4; + + #[inline_always] + fn deserialize(serialized: [Field; 4]) -> Self { + let mut offset: u32 = 0_u32; + let mut member_fields: [Field; 1] = [0_Field; 1]; + for i in 0_u32..::N { + member_fields[i] = serialized[i + offset]; + } + let x: Field = ::deserialize(member_fields); + offset = offset + ::N; + let mut member_fields: [Field; 3] = [0_Field; 3]; + for i in 0_u32..<[Field; 3] as Deserialize>::N { + member_fields[i] = serialized[i + offset]; + } + let y: [Field; 3] = <[Field; 3] as Deserialize>::deserialize(member_fields); + offset = offset + <[Field; 3] as Deserialize>::N; + Self { x: x, y: y } + } +} + +fn main() { + let foo: Foo = Foo { x: 0_Field, y: [1_Field, 2_Field, 3_Field] }; + let serialized: [Field; 4] = foo.serialize(); + let deserialized: Foo = >::deserialize(serialized); + assert(foo == deserialized); +} + +mod meta { + pub comptime fn derive_serialize(s: TypeDefinition) -> Quoted { + let typ: Type = s.as_type(); + let nested_struct: (TypeDefinition, [Type]) = typ.as_data_type().unwrap(); + let params: [(Quoted, Type, Quoted)] = nested_struct.0.fields(nested_struct.1); + let components_of_definition_of_n: [Quoted] = params + .map(|(_, param_type, _): (Quoted, Type, Quoted)| -> Quoted { + quote { <$param_type as Serialize>::N } + }); + let right_hand_side_of_definition_of_n: Quoted = + components_of_definition_of_n.join(quote { + }); + let array_of_quotes_serializing_each_struct_member: [Quoted] = params + .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| -> Quoted { + quote { + let serialized_member = self.$param_name.serialize(); + let serialized_member_len = < $param_type as Serialize > ::N; + for i in 0..serialized_member_len { + result[i + offset] = serialized_member[i]; + } + offset += serialized_member_len; + } + }); + let serialization_of_struct_members: Quoted = + array_of_quotes_serializing_each_struct_member.join(quote { }); + quote { + impl Serialize for $typ { + let N: u32 = $right_hand_side_of_definition_of_n; + #[inline_always]fn serialize(self) -> [Field; + Self::N] { + let mut result = [0; + _]; + let mut offset = 0; + $serialization_of_struct_members result + } + } + } + } + + pub(crate) comptime fn derive_deserialize(s: TypeDefinition) -> Quoted { + let typ: Type = s.as_type(); + let nested_struct: (TypeDefinition, [Type]) = typ.as_data_type().unwrap(); + let params: [(Quoted, Type, Quoted)] = nested_struct.0.fields(nested_struct.1); + let components_of_definition_of_n: [Quoted] = params + .map(|(_, param_type, _): (Quoted, Type, Quoted)| -> Quoted { + quote { <$param_type as Deserialize>::N } + }); + let serialized_len: Quoted = components_of_definition_of_n.join(quote { + }); + let array_of_quotes_deserializing_each_struct_member: [Quoted] = params + .map(|(param_name, param_type, _): (Quoted, Type, Quoted)| -> Quoted { + quote { + let mut member_fields = [0; + < $param_type as Deserialize > ::N]; + for i in 0.. < $param_type as Deserialize > ::N { + member_fields[i] = serialized[i + offset]; + } + let $param_name = < $param_type as Deserialize > ::deserialize(member_fields); + offset += < $param_type as Deserialize > ::N; + } + }); + let deserialization_of_struct_members: Quoted = + array_of_quotes_deserializing_each_struct_member.join(quote { }); + let struct_members: Quoted = params + .map(|(param_name, _, _): (Quoted, Type, Quoted)| -> Quoted quote { $param_name }) + .join(quote { , }); + quote { + impl Deserialize for $typ { + let N: u32 = $serialized_len; + #[inline_always]fn deserialize(serialized: [Field; + Self::N]) -> Self { + let mut offset = 0; + $deserialization_of_struct_members Self { + $struct_members + } + } + } + } + } +} diff --git a/tooling/nargo_cli/tests/snapshots/execution_success/trait_associated_constant/execute__tests__expanded.snap b/tooling/nargo_cli/tests/snapshots/execution_success/trait_associated_constant/execute__tests__expanded.snap new file mode 100644 index 00000000000..9ca93663659 --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/execution_success/trait_associated_constant/execute__tests__expanded.snap @@ -0,0 +1,25 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: expanded_code +--- +pub trait Trait { + let N: u32; + + fn foo() -> u32; +} + +struct Foo {} + +impl Trait for Foo { + let N: u32 = A + B; + + fn foo() -> u32 { + Self::N + } +} + +fn main() { + let x: u32 = Foo::<10, 20>::foo(); + assert(x == 30_u32); + () +}