From eda904328b269b5926f8a82ab82e52a485903bbe Mon Sep 17 00:00:00 2001 From: Michael J Klein Date: Tue, 17 Sep 2024 15:11:21 -0400 Subject: [PATCH] chore!: removing implicit numeric generics (#5837) # Description ## Problem\* - Resolves https://github.com/noir-lang/noir/issues/5156 - Resolves https://github.com/noir-lang/noir/issues/5447 ## Summary\* ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [x] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: Maxim Vezenov Co-authored-by: jfecher Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- aztec_macros/src/utils/hir_utils.rs | 6 +- compiler/noirc_driver/src/abi_gen.rs | 2 +- .../src/elaborator/expressions.rs | 10 +- compiler/noirc_frontend/src/elaborator/mod.rs | 63 +---- .../noirc_frontend/src/elaborator/types.rs | 123 ++++----- .../src/hir/comptime/hir_to_display_ast.rs | 10 +- .../src/hir/comptime/interpreter/builtin.rs | 6 +- .../noirc_frontend/src/hir/comptime/value.rs | 4 +- .../src/hir/resolution/errors.rs | 11 - compiler/noirc_frontend/src/hir_def/types.rs | 234 ++++++++---------- .../src/hir_def/types/arithmetic.rs | 32 ++- .../src/monomorphization/errors.rs | 5 + .../src/monomorphization/mod.rs | 10 +- compiler/noirc_frontend/src/node_interner.rs | 2 +- .../noirc_frontend/src/parser/parser.rs:28:9 | 45 ---- compiler/noirc_frontend/src/tests.rs | 119 +++++---- docs/docs/noir/concepts/data_types/slices.mdx | 2 +- docs/docs/noir/concepts/generics.md | 63 +++-- docs/docs/noir/concepts/globals.md | 2 +- docs/docs/noir/concepts/traits.md | 2 +- .../cryptographic_primitives/hashes.mdx | 2 +- noir_stdlib/src/hash/keccak.nr | 4 +- noir_stdlib/src/hash/mimc.nr | 2 +- .../closure_explicit_types/src/main.nr | 2 +- .../macros_in_comptime/src/main.nr | 5 +- .../numeric_generics/src/main.nr | 6 +- .../regression_4635/src/main.nr | 2 +- .../serialize/src/main.nr | 6 +- .../trait_generics/src/main.nr | 4 +- .../execution_success/7_function/src/main.nr | 2 +- .../aes128_encrypt/src/main.nr | 2 +- .../execution_success/array_len/src/main.nr | 6 +- .../array_to_slice/src/main.nr | 2 +- .../brillig_cow_regression/src/main.nr | 20 +- .../brillig_keccak/src/main.nr | 2 +- .../cast_and_shift_global/src/main.nr | 6 +- .../execution_success/debug_logs/src/main.nr | 4 +- .../fold_numeric_generic_poseidon/src/main.nr | 2 +- .../execution_success/generics/src/main.nr | 6 +- .../global_consts/src/foo.nr | 4 +- .../global_consts/src/foo/bar.nr | 2 +- .../global_consts/src/main.nr | 28 +-- .../execution_success/hashmap/src/main.nr | 2 +- .../execution_success/hashmap/src/utils.nr | 2 +- .../src/main.nr | 4 +- .../execution_success/regression/src/main.nr | 4 +- .../regression_4088/src/main.nr | 2 +- .../regression_4124/src/main.nr | 2 +- .../execution_success/schnorr/src/main.nr | 12 +- .../noir_test_success/bounded_vec/src/main.nr | 2 +- tooling/lsp/src/requests/completion.rs | 2 +- tooling/lsp/src/requests/hover.rs | 2 +- .../src/trait_impl_method_stub_generator.rs | 2 +- tooling/noir_codegen/test/test_lib/src/lib.nr | 4 +- 54 files changed, 405 insertions(+), 505 deletions(-) delete mode 100644 compiler/noirc_frontend/src/parser/parser.rs:28:9 diff --git a/aztec_macros/src/utils/hir_utils.rs b/aztec_macros/src/utils/hir_utils.rs index 200ce3099cb..4f1ef78b474 100644 --- a/aztec_macros/src/utils/hir_utils.rs +++ b/aztec_macros/src/utils/hir_utils.rs @@ -74,7 +74,7 @@ pub fn signature_of_type(typ: &Type) -> String { Type::FieldElement => "Field".to_owned(), Type::Bool => "bool".to_owned(), Type::Array(len, typ) => { - if let Type::Constant(len) = **len { + if let Type::Constant(len, _) = **len { format!("[{};{len}]", signature_of_type(typ)) } else { unimplemented!("Cannot generate signature for array with length type {:?}", typ) @@ -90,7 +90,7 @@ pub fn signature_of_type(typ: &Type) -> String { format!("({})", fields.join(",")) } Type::String(len_typ) => { - if let Type::Constant(len) = **len_typ { + if let Type::Constant(len, _) = **len_typ { format!("str<{len}>") } else { unimplemented!( @@ -326,7 +326,7 @@ pub fn get_serialized_length( let serialized_trait_impl = serialized_trait_impl_shared.borrow(); match serialized_trait_impl.trait_generics.first().unwrap() { - Type::Constant(value) => Ok(*value), + Type::Constant(value, _) => Ok(*value), _ => Err(MacroError { primary_message: format!("{} length for {} must be a constant", trait_name, typ), secondary_message: None, diff --git a/compiler/noirc_driver/src/abi_gen.rs b/compiler/noirc_driver/src/abi_gen.rs index e2692349baa..be89b24fee5 100644 --- a/compiler/noirc_driver/src/abi_gen.rs +++ b/compiler/noirc_driver/src/abi_gen.rs @@ -99,7 +99,7 @@ pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType { } Type::Error | Type::Unit - | Type::Constant(_) + | Type::Constant(..) | Type::InfixExpr(..) | Type::TraitAsType(..) | Type::TypeVariable(_, _) diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 311c8f401be..f8b7e7ee4e1 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -29,7 +29,7 @@ use crate::{ }, node_interner::{DefinitionKind, ExprId, FuncId, InternedStatementKind, TraitMethodId}, token::Tokens, - QuotedType, Shared, StructType, Type, + Kind, QuotedType, Shared, StructType, Type, }; use super::{Elaborator, LambdaContext}; @@ -162,7 +162,7 @@ impl<'context> Elaborator<'context> { (Lit(int), self.polymorphic_integer_or_field()) } Literal::Str(str) | Literal::RawStr(str, _) => { - let len = Type::Constant(str.len() as u32); + let len = Type::Constant(str.len() as u32, Kind::u32()); (Lit(HirLiteral::Str(str)), Type::String(Box::new(len))) } Literal::FmtStr(str) => self.elaborate_fmt_string(str, span), @@ -204,7 +204,7 @@ impl<'context> Elaborator<'context> { elem_id }); - let length = Type::Constant(elements.len() as u32); + let length = Type::Constant(elements.len() as u32, Kind::u32()); (HirArrayLiteral::Standard(elements), first_elem_type, length) } ArrayLiteral::Repeated { repeated_element, length } => { @@ -215,7 +215,7 @@ impl<'context> Elaborator<'context> { UnresolvedTypeExpression::Constant(0, span) }); - let length = self.convert_expression_type(length); + let length = self.convert_expression_type(length, span); let (repeated_element, elem_type) = self.elaborate_expression(*repeated_element); let length_clone = length.clone(); @@ -268,7 +268,7 @@ impl<'context> Elaborator<'context> { } } - let len = Type::Constant(str.len() as u32); + let len = Type::Constant(str.len() as u32, Kind::u32()); let typ = Type::FmtString(Box::new(len), Box::new(Type::Tuple(capture_types))); (HirExpression::Literal(HirLiteral::FmtStr(str, fmt_str_idents)), typ) } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index dbfbe9d4558..905cdc3df79 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -17,7 +17,7 @@ use crate::{ }, hir_def::{ expr::{HirCapturedVar, HirIdent}, - function::{FunctionBody, Parameters}, + function::FunctionBody, traits::TraitConstraint, types::{Generics, Kind, ResolvedGeneric}, }, @@ -415,7 +415,6 @@ impl<'context> Elaborator<'context> { self.add_existing_variable_to_scope(name, parameter.clone(), true); } - self.declare_numeric_generics(&func_meta.parameters, func_meta.return_type()); self.add_trait_constraints_to_scope(&func_meta); let (hir_func, body_type) = match kind { @@ -896,44 +895,6 @@ impl<'context> Elaborator<'context> { } } - // TODO(https://github.com/noir-lang/noir/issues/5156): Remove implicit numeric generics - fn declare_numeric_generics(&mut self, params: &Parameters, return_type: &Type) { - if self.generics.is_empty() { - return; - } - - for (name_to_find, type_variable) in Self::find_numeric_generics(params, return_type) { - // Declare any generics to let users use numeric generics in scope. - // Don't issue a warning if these are unused - // - // We can fail to find the generic in self.generics if it is an implicit one created - // by the compiler. This can happen when, e.g. eliding array lengths using the slice - // syntax [T]. - if let Some(ResolvedGeneric { name, span, kind, .. }) = - self.generics.iter_mut().find(|generic| generic.name.as_ref() == &name_to_find) - { - let scope = self.scopes.get_mut_scope(); - let value = scope.find(&name_to_find); - if value.is_some() { - // With the addition of explicit numeric generics we do not want to introduce numeric generics in this manner - // However, this is going to be a big breaking change so for now we simply issue a warning while users have time - // to transition to the new syntax - // e.g. this code would break with a duplicate definition error: - // ``` - // fn foo(arr: [Field; N]) { } - // ``` - continue; - } - *kind = Kind::Numeric(Box::new(Type::default_int_type())); - let ident = Ident::new(name.to_string(), *span); - let definition = DefinitionKind::GenericType(type_variable); - self.add_variable_decl_inner(ident.clone(), false, false, false, definition); - - self.push_err(ResolverError::UseExplicitNumericGeneric { ident }); - } - } - } - fn add_trait_constraints_to_scope(&mut self, func_meta: &FuncMeta) { for constraint in &func_meta.trait_constraints { let object = constraint.typ.clone(); @@ -1187,28 +1148,6 @@ impl<'context> Elaborator<'context> { let fields_len = fields.len(); self.interner.update_struct(*type_id, |struct_def| { struct_def.set_fields(fields); - - // TODO(https://github.com/noir-lang/noir/issues/5156): Remove this with implicit numeric generics - // This is only necessary for resolving named types when implicit numeric generics are used. - let mut found_names = Vec::new(); - struct_def.find_numeric_generics_in_fields(&mut found_names); - for generic in struct_def.generics.iter_mut() { - for found_generic in found_names.iter() { - if found_generic == generic.name.as_str() { - if matches!(generic.kind, Kind::Normal) { - let ident = Ident::new(generic.name.to_string(), generic.span); - self.errors.push(( - CompilationError::ResolverError( - ResolverError::UseExplicitNumericGeneric { ident }, - ), - self.file, - )); - generic.kind = Kind::Numeric(Box::new(Type::default_int_type())); - } - break; - } - } - } }); for field_index in 0..fields_len { diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 46c779dc4ff..c800b3b2c33 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -12,6 +12,7 @@ use crate::{ }, hir::{ comptime::{Interpreter, Value}, + def_collector::dc_crate::CompilationError, def_map::ModuleDefId, resolution::errors::ResolverError, type_check::{ @@ -76,45 +77,22 @@ impl<'context> Elaborator<'context> { FieldElement => Type::FieldElement, Array(size, elem) => { let elem = Box::new(self.resolve_type_inner(*elem, kind)); - let mut size = self.convert_expression_type(size); - // TODO(https://github.com/noir-lang/noir/issues/5156): Remove this once we only have explicit numeric generics - if let Type::NamedGeneric(type_var, name, _) = size { - size = Type::NamedGeneric( - type_var, - name, - Kind::Numeric(Box::new(Type::default_int_type())), - ); - } + let size = self.convert_expression_type(size, span); Type::Array(Box::new(size), elem) } Slice(elem) => { let elem = Box::new(self.resolve_type_inner(*elem, kind)); Type::Slice(elem) } - Expression(expr) => self.convert_expression_type(expr), + Expression(expr) => self.convert_expression_type(expr, span), Integer(sign, bits) => Type::Integer(sign, bits), Bool => Type::Bool, String(size) => { - let mut resolved_size = self.convert_expression_type(size); - // TODO(https://github.com/noir-lang/noir/issues/5156): Remove this once we only have explicit numeric generics - if let Type::NamedGeneric(type_var, name, _) = resolved_size { - resolved_size = Type::NamedGeneric( - type_var, - name, - Kind::Numeric(Box::new(Type::default_int_type())), - ); - } + let resolved_size = self.convert_expression_type(size, span); Type::String(Box::new(resolved_size)) } FormatString(size, fields) => { - let mut resolved_size = self.convert_expression_type(size); - if let Type::NamedGeneric(type_var, name, _) = resolved_size { - resolved_size = Type::NamedGeneric( - type_var, - name, - Kind::Numeric(Box::new(Type::default_int_type())), - ); - } + let resolved_size = self.convert_expression_type(size, span); let fields = self.resolve_type_inner(*fields, kind); Type::FmtString(Box::new(resolved_size), Box::new(fields)) } @@ -191,26 +169,18 @@ impl<'context> Elaborator<'context> { _ => (), } - // Check that any types with a type kind match the expected type kind supplied to this function - // TODO(https://github.com/noir-lang/noir/issues/5156): make this named generic check more general with `*resolved_kind != kind` - // as implicit numeric generics still existing makes this check more challenging to enforce - // An example of a more general check that we should switch to: - // if resolved_type.kind() != kind.clone() { - // let expected_typ_err = CompilationError::TypeError(TypeCheckError::TypeKindMismatch { - // expected_kind: kind.to_string(), - // expr_kind: resolved_type.kind().to_string(), - // expr_span: span.expect("Type should have span"), - // }); - // self.errors.push((expected_typ_err, self.file)); - // return Type::Error; - // } - if let Type::NamedGeneric(_, name, resolved_kind) = &resolved_type { - if matches!(resolved_kind, Kind::Numeric { .. }) && matches!(kind, Kind::Normal) { - let expected_typ_err = - ResolverError::NumericGenericUsedForType { name: name.to_string(), span }; - self.push_err(expected_typ_err); - return Type::Error; - } + if !kind.matches_opt(resolved_type.kind()) { + let expected_typ_err = CompilationError::TypeError(TypeCheckError::TypeKindMismatch { + expected_kind: kind.to_string(), + expr_kind: resolved_type + .kind() + .as_ref() + .map(Kind::to_string) + .unwrap_or("unknown".to_string()), + expr_span: span, + }); + self.errors.push((expected_typ_err, self.file)); + return Type::Error; } resolved_type @@ -441,30 +411,61 @@ impl<'context> Elaborator<'context> { let reference_location = Location::new(path.span(), self.file); self.interner.add_global_reference(id, reference_location); + let kind = self + .interner + .get_global_let_statement(id) + .map(|let_statement| Kind::Numeric(Box::new(let_statement.r#type))) + .unwrap_or(Kind::u32()); - Some(Type::Constant(self.eval_global_as_array_length(id, path))) + Some(Type::Constant(self.eval_global_as_array_length(id, path), kind)) } _ => None, } } - pub(super) fn convert_expression_type(&mut self, length: UnresolvedTypeExpression) -> Type { + pub(super) fn convert_expression_type( + &mut self, + length: UnresolvedTypeExpression, + span: Span, + ) -> Type { match length { UnresolvedTypeExpression::Variable(path) => { - self.lookup_generic_or_global_type(&path).unwrap_or_else(|| { - self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); - Type::Constant(0) - }) + let resolved_length = + self.lookup_generic_or_global_type(&path).unwrap_or_else(|| { + self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); + Type::Constant(0, Kind::u32()) + }); + + if let Type::NamedGeneric(ref _type_var, ref _name, ref kind) = resolved_length { + if !kind.is_numeric() { + self.push_err(TypeCheckError::TypeKindMismatch { + expected_kind: Kind::u32().to_string(), + expr_kind: kind.to_string(), + expr_span: span, + }); + return Type::Error; + } + } + resolved_length } - UnresolvedTypeExpression::Constant(int, _) => Type::Constant(int), + UnresolvedTypeExpression::Constant(int, _span) => Type::Constant(int, Kind::u32()), UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, span) => { - let lhs = self.convert_expression_type(*lhs); - let rhs = self.convert_expression_type(*rhs); + let (lhs_span, rhs_span) = (lhs.span(), rhs.span()); + let lhs = self.convert_expression_type(*lhs, lhs_span); + let rhs = self.convert_expression_type(*rhs, rhs_span); match (lhs, rhs) { - (Type::Constant(lhs), Type::Constant(rhs)) => { + (Type::Constant(lhs, lhs_kind), Type::Constant(rhs, rhs_kind)) => { + if lhs_kind != rhs_kind { + self.push_err(TypeCheckError::TypeKindMismatch { + expected_kind: lhs_kind.to_string(), + expr_kind: rhs_kind.to_string(), + expr_span: span, + }); + return Type::Error; + } if let Some(result) = op.function(lhs, rhs) { - Type::Constant(result) + Type::Constant(result, lhs_kind) } else { self.push_err(ResolverError::OverflowInType { lhs, op, rhs, span }); Type::Error @@ -1686,7 +1687,7 @@ impl<'context> Elaborator<'context> { | Type::Unit | Type::Error | Type::TypeVariable(_, _) - | Type::Constant(_) + | Type::Constant(..) | Type::NamedGeneric(_, _, _) | Type::Quoted(_) | Type::Forall(_, _) => (), @@ -1727,7 +1728,7 @@ impl<'context> Elaborator<'context> { Type::Struct(struct_type, generics) => { for (i, generic) in generics.iter().enumerate() { if let Type::NamedGeneric(type_variable, name, _) = generic { - if struct_type.borrow().generic_is_numeric(i) { + if struct_type.borrow().generics[i].is_numeric() { found.insert(name.to_string(), type_variable.clone()); } } else { @@ -1738,7 +1739,7 @@ impl<'context> Elaborator<'context> { Type::Alias(alias, generics) => { for (i, generic) in generics.iter().enumerate() { if let Type::NamedGeneric(type_variable, name, _) = generic { - if alias.borrow().generic_is_numeric(i) { + if alias.borrow().generics[i].is_numeric() { found.insert(name.to_string(), type_variable.clone()); } } else { diff --git a/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs b/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs index 0f2b9ee4280..4a159c682b7 100644 --- a/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs +++ b/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs @@ -345,7 +345,7 @@ impl Type { // Since there is no UnresolvedTypeData equivalent for Type::Forall, we use // this to ignore this case since it shouldn't be needed anyway. Type::Forall(_, typ) => return typ.to_display_ast(), - Type::Constant(_) => panic!("Type::Constant where a type was expected: {self:?}"), + Type::Constant(..) => panic!("Type::Constant where a type was expected: {self:?}"), Type::Quoted(quoted_type) => UnresolvedTypeData::Quoted(*quoted_type), Type::Error => UnresolvedTypeData::Error, Type::InfixExpr(lhs, op, rhs) => { @@ -365,7 +365,7 @@ impl Type { let span = Span::default(); match self.follow_bindings() { - Type::Constant(length) => UnresolvedTypeExpression::Constant(length, span), + Type::Constant(length, _kind) => UnresolvedTypeExpression::Constant(length, span), Type::NamedGeneric(_var, name, _kind) => { let path = Path::from_single(name.as_ref().clone(), span); UnresolvedTypeExpression::Variable(path) @@ -408,10 +408,10 @@ impl HirArrayLiteral { HirArrayLiteral::Repeated { repeated_element, length } => { let repeated_element = Box::new(repeated_element.to_display_ast(interner)); let length = match length { - Type::Constant(length) => { + Type::Constant(length, _kind) => { let literal = Literal::Integer((*length as u128).into(), false); - let kind = ExpressionKind::Literal(literal); - Box::new(Expression::new(kind, span)) + let expr_kind = ExpressionKind::Literal(literal); + Box::new(Expression::new(expr_kind, span)) } other => panic!("Cannot convert non-constant type for repeated array literal from Hir -> Ast: {other:?}"), }; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 9833cf27565..595ca5dedc0 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -302,7 +302,7 @@ fn str_as_bytes( let bytes: im::Vector = string.bytes().map(Value::U8).collect(); let byte_array_type = Type::Array( - Box::new(Type::Constant(bytes.len() as u32)), + Box::new(Type::Constant(bytes.len() as u32, Kind::u32())), Box::new(Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight)), ); Ok(Value::Array(bytes, byte_array_type)) @@ -776,7 +776,7 @@ fn to_le_radix( let value = get_field(value)?; let radix = get_u32(radix)?; let limb_count = if let Type::Array(length, _) = return_type { - if let Type::Constant(limb_count) = *length { + if let Type::Constant(limb_count, _kind) = *length { limb_count } else { return Err(InterpreterError::TypeAnnotationsNeededForMethodCall { location }); @@ -1194,7 +1194,7 @@ fn zeroed(return_type: Type) -> IResult { // Optimistically assume we can resolve this type later or that the value is unused Type::TypeVariable(_, _) | Type::Forall(_, _) - | Type::Constant(_) + | Type::Constant(..) | Type::InfixExpr(..) | Type::Quoted(_) | Type::Error diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 31971fc63b7..f2cb714deb4 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -27,7 +27,7 @@ use crate::{ node_interner::{ExprId, FuncId, InternedStatementKind, StmtId, TraitId, TraitImplId}, parser::{self, NoirParser, TopLevelStatement}, token::{SpannedToken, Token, Tokens}, - QuotedType, Shared, Type, TypeBindings, + Kind, QuotedType, Shared, Type, TypeBindings, }; use rustc_hash::FxHashMap as HashMap; @@ -124,7 +124,7 @@ impl Value { Value::U32(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo), Value::U64(_) => Type::Integer(Signedness::Unsigned, IntegerBitSize::SixtyFour), Value::String(value) => { - let length = Type::Constant(value.len() as u32); + let length = Type::Constant(value.len() as u32, Kind::u32()); Type::String(Box::new(length)) } Value::FormatString(_, typ) => return Cow::Borrowed(typ), diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index 08f57ae562a..1e7f29527e2 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -102,8 +102,6 @@ pub enum ResolverError { FoldAttributeOnUnconstrained { ident: Ident }, #[error("The only supported types of numeric generics are integers, fields, and booleans")] UnsupportedNumericGenericType { ident: Ident, typ: Type }, - #[error("Numeric generics should be explicit")] - UseExplicitNumericGeneric { ident: Ident }, #[error("expected type, found numeric generic parameter")] NumericGenericUsedForType { name: String, span: Span }, #[error("Invalid array length construction")] @@ -439,15 +437,6 @@ impl<'a> From<&'a ResolverError> for Diagnostic { ident.0.span(), ) } - ResolverError::UseExplicitNumericGeneric { ident } => { - let name = &ident.0.contents; - - Diagnostic::simple_warning( - String::from("Noir now supports explicit numeric generics. Support for implicit numeric generics will be removed in the following release."), - format!("Numeric generic `{name}` should now be specified with `let {name}: `"), - ident.0.span(), - ) - } ResolverError::NumericGenericUsedForType { name, span } => { Diagnostic::simple_error( format!("expected type, found numeric generic parameter {name}"), diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 37a1bf6ddf7..a24ee2635be 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -112,7 +112,7 @@ pub enum Type { /// A type-level integer. Included to let an Array's size type variable /// bind to an integer without special checks to bind it to a non-type. - Constant(u32), + Constant(u32, Kind), /// The type of quoted code in macros. This is always a comptime-only type Quoted(QuotedType), @@ -138,6 +138,27 @@ pub enum Kind { Numeric(Box), } +impl Kind { + pub(crate) fn is_error(&self) -> bool { + match self { + Self::Numeric(typ) => **typ == Type::Error, + _ => false, + } + } + + pub(crate) fn is_numeric(&self) -> bool { + matches!(self, Self::Numeric { .. }) + } + + pub(crate) fn matches_opt(&self, other: Option) -> bool { + other.as_ref().map_or(true, |other_kind| self == other_kind) + } + + pub(crate) fn u32() -> Self { + Self::Numeric(Box::new(Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo))) + } +} + impl std::fmt::Display for Kind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -211,6 +232,10 @@ impl ResolvedGeneric { pub fn as_named_generic(self) -> Type { Type::NamedGeneric(self.type_var, self.name, self.kind) } + + pub(crate) fn is_numeric(&self) -> bool { + self.kind.is_numeric() + } } enum FunctionCoercionResult { @@ -328,15 +353,6 @@ impl StructType { } } - /// True if the given index is the same index as a generic type of this struct - /// which is expected to be a numeric generic. - /// This is needed because we infer type kinds in Noir and don't have extensive kind checking. - /// TODO(https://github.com/noir-lang/noir/issues/5156): This is outdated and we should remove this implicit searching for numeric generics - pub fn generic_is_numeric(&self, index_of_generic: usize) -> bool { - let target_id = self.generics[index_of_generic].type_var.id(); - self.fields.iter().any(|(_, field)| field.contains_numeric_typevar(target_id)) - } - /// Instantiate this struct type, returning a Vec of the new generic args (in /// the same order as self.generics) pub fn instantiate(&self, interner: &mut NodeInterner) -> Vec { @@ -419,14 +435,6 @@ impl TypeAlias { self.typ.substitute(&substitutions) } - - /// True if the given index is the same index as a generic type of this alias - /// which is expected to be a numeric generic. - /// This is needed because we infer type kinds in Noir and don't have extensive kind checking. - pub fn generic_is_numeric(&self, index_of_generic: usize) -> bool { - let target_id = self.generics[index_of_generic].type_var.id(); - self.typ.contains_numeric_typevar(target_id) - } } /// A shared, mutable reference to some T. @@ -668,7 +676,7 @@ impl std::fmt::Display for Type { TypeBinding::Unbound(_) if name.is_empty() => write!(f, "_"), TypeBinding::Unbound(_) => write!(f, "{name}"), }, - Type::Constant(x) => x.fmt(f), + Type::Constant(x, _kind) => write!(f, "{x}"), Type::Forall(typevars, typ) => { let typevars = vecmap(typevars, |var| var.id().to_string()); write!(f, "forall {}. {}", typevars.join(" "), typ) @@ -826,78 +834,6 @@ impl Type { ) } - fn contains_numeric_typevar(&self, target_id: TypeVariableId) -> bool { - // True if the given type is a NamedGeneric with the target_id - let named_generic_id_matches_target = |typ: &Type| { - if let Type::NamedGeneric(type_variable, _, _) = typ { - match &*type_variable.borrow() { - TypeBinding::Bound(_) => { - unreachable!("Named generics should not be bound until monomorphization") - } - TypeBinding::Unbound(id) => target_id == *id, - } - } else { - false - } - }; - - match self { - Type::FieldElement - | Type::Integer(_, _) - | Type::Bool - | Type::Unit - | Type::Error - | Type::TypeVariable(_, _) - | Type::Constant(_) - | Type::NamedGeneric(_, _, _) - | Type::Forall(_, _) - | Type::Quoted(_) => false, - - Type::TraitAsType(_, _, generics) => { - generics.ordered.iter().any(|generic| generic.contains_numeric_typevar(target_id)) - || generics.named.iter().any(|typ| typ.typ.contains_numeric_typevar(target_id)) - } - Type::Array(length, elem) => { - elem.contains_numeric_typevar(target_id) || named_generic_id_matches_target(length) - } - Type::Slice(elem) => elem.contains_numeric_typevar(target_id), - Type::Tuple(fields) => { - fields.iter().any(|field| field.contains_numeric_typevar(target_id)) - } - Type::Function(parameters, return_type, env, _unconstrained) => { - parameters.iter().any(|parameter| parameter.contains_numeric_typevar(target_id)) - || return_type.contains_numeric_typevar(target_id) - || env.contains_numeric_typevar(target_id) - } - Type::Struct(struct_type, generics) => { - generics.iter().enumerate().any(|(i, generic)| { - if named_generic_id_matches_target(generic) { - struct_type.borrow().generic_is_numeric(i) - } else { - generic.contains_numeric_typevar(target_id) - } - }) - } - Type::Alias(alias, generics) => generics.iter().enumerate().any(|(i, generic)| { - if named_generic_id_matches_target(generic) { - alias.borrow().generic_is_numeric(i) - } else { - generic.contains_numeric_typevar(target_id) - } - }), - Type::MutableReference(element) => element.contains_numeric_typevar(target_id), - Type::String(length) => named_generic_id_matches_target(length), - Type::FmtString(length, elements) => { - elements.contains_numeric_typevar(target_id) - || named_generic_id_matches_target(length) - } - Type::InfixExpr(lhs, _op, rhs) => { - lhs.contains_numeric_typevar(target_id) || rhs.contains_numeric_typevar(target_id) - } - } - } - - /// TODO(https://github.com/noir-lang/noir/issues/5156): Remove with explicit numeric generics pub fn find_numeric_type_vars(&self, found_names: &mut Vec) { // Return whether the named generic has a TypeKind::Numeric and save its name let named_generic_is_numeric = |typ: &Type, found_names: &mut Vec| { @@ -915,7 +851,7 @@ impl Type { | Type::Bool | Type::Unit | Type::Error - | Type::Constant(_) + | Type::Constant(_, _) | Type::Forall(_, _) | Type::Quoted(_) => {} @@ -998,7 +934,7 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Unit - | Type::Constant(_) + | Type::Constant(_, _) | Type::Error => true, Type::FmtString(_, _) @@ -1044,7 +980,7 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Unit - | Type::Constant(_) + | Type::Constant(_, _) | Type::TypeVariable(_, _) | Type::NamedGeneric(_, _, _) | Type::InfixExpr(..) @@ -1087,7 +1023,7 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Unit - | Type::Constant(_) + | Type::Constant(_, _) | Type::Slice(_) | Type::Function(_, _, _, _) | Type::FmtString(_, _) @@ -1170,35 +1106,53 @@ impl Type { } } - // TODO(https://github.com/noir-lang/noir/issues/5156): Bring back this method when we remove implicit numeric generics - // It has been commented out as to not trigger clippy for an unused method - // pub(crate) fn kind(&self) -> Kind { - // match self { - // Type::NamedGeneric(_, _, kind) => kind.clone(), - // Type::Constant(_) => Kind::Numeric(Box::new(Type::Integer( - // Signedness::Unsigned, - // IntegerBitSize::ThirtyTwo, - // ))), - // Type::FieldElement - // | Type::Array(_, _) - // | Type::Slice(_) - // | Type::Integer(_, _) - // | Type::Bool - // | Type::String(_) - // | Type::FmtString(_, _) - // | Type::Unit - // | Type::Tuple(_) - // | Type::Struct(_, _) - // | Type::Alias(_, _) - // | Type::TypeVariable(_, _) - // | Type::TraitAsType(_, _, _) - // | Type::Function(_, _, _) - // | Type::MutableReference(_) - // | Type::Forall(_, _) - // | Type::Quoted(_) - // | Type::Error => Kind::Normal, - // } - // } + pub(crate) fn kind(&self) -> Option { + match self { + Type::NamedGeneric(_, _, kind) => Some(kind.clone()), + Type::Constant(_, kind) => Some(kind.clone()), + Type::TypeVariable(var, _) => match *var.borrow() { + TypeBinding::Bound(ref typ) => typ.kind(), + TypeBinding::Unbound(_) => None, + }, + Type::InfixExpr(lhs, _op, rhs) => Some(lhs.infix_kind(rhs)), + Type::FieldElement + | Type::Array(..) + | Type::Slice(..) + | Type::Integer(..) + | Type::Bool + | Type::String(..) + | Type::FmtString(..) + | Type::Unit + | Type::Tuple(..) + | Type::Struct(..) + | Type::Alias(..) + | Type::TraitAsType(..) + | Type::Function(..) + | Type::MutableReference(..) + | Type::Forall(..) + | Type::Quoted(..) + | Type::Error => Some(Kind::Normal), + } + } + + /// if both Kind's are equal to Some(_), return that Kind, + /// otherwise return a Kind error + /// if both Kind's are None, default to u32 + /// if exactly one Kind is None, return the other one + fn infix_kind(&self, other: &Self) -> Kind { + match (self.kind(), other.kind()) { + (Some(self_kind), Some(other_kind)) => { + if self_kind == other_kind { + self_kind + } else { + Kind::Numeric(Box::new(Type::Error)) + } + } + (None, None) => Kind::u32(), + (Some(self_kind), None) => self_kind, + (None, Some(other_kind)) => other_kind, + } + } /// Returns the number of field elements required to represent the type once encoded. pub fn field_count(&self) -> u32 { @@ -1231,7 +1185,7 @@ impl Type { | Type::Function(_, _, _, _) | Type::MutableReference(_) | Type::Forall(_, _) - | Type::Constant(_) + | Type::Constant(_, _) | Type::Quoted(_) | Type::Slice(_) | Type::InfixExpr(..) @@ -1562,9 +1516,9 @@ impl Type { } } - (Constant(value), other) | (other, Constant(value)) => { + (Constant(value, kind), other) | (other, Constant(value, kind)) => { if let Some(other_value) = other.evaluate_to_u32() { - if *value == other_value { + if *value == other_value && kind.matches_opt(other.kind()) { Ok(()) } else { Err(UnificationError) @@ -1572,7 +1526,11 @@ impl Type { } else if let InfixExpr(lhs, op, rhs) = other { if let Some(inverse) = op.inverse() { // Handle cases like `4 = a + b` by trying to solve to `a = 4 - b` - let new_type = InfixExpr(Box::new(Constant(*value)), inverse, rhs.clone()); + let new_type = InfixExpr( + Box::new(Constant(*value, kind.clone())), + inverse, + rhs.clone(), + ); new_type.try_unify(lhs, bindings)?; Ok(()) } else { @@ -1731,7 +1689,7 @@ impl Type { match self.canonicalize() { Type::Array(len, _elem) => len.evaluate_to_u32(), - Type::Constant(x) => Some(x), + Type::Constant(x, _) => Some(x), Type::InfixExpr(lhs, op, rhs) => { let lhs = lhs.evaluate_to_u32()?; let rhs = rhs.evaluate_to_u32()?; @@ -2009,7 +1967,7 @@ impl Type { Type::FieldElement | Type::Integer(_, _) | Type::Bool - | Type::Constant(_) + | Type::Constant(_, _) | Type::Error | Type::Quoted(_) | Type::Unit => self.clone(), @@ -2057,7 +2015,7 @@ impl Type { Type::FieldElement | Type::Integer(_, _) | Type::Bool - | Type::Constant(_) + | Type::Constant(_, _) | Type::Error | Type::Quoted(_) | Type::Unit => false, @@ -2125,7 +2083,7 @@ impl Type { // Expect that this function should only be called on instantiated types Forall(..) => unreachable!(), - FieldElement | Integer(_, _) | Bool | Constant(_) | Unit | Quoted(_) | Error => { + FieldElement | Integer(_, _) | Bool | Constant(_, _) | Unit | Quoted(_) | Error => { self.clone() } } @@ -2141,7 +2099,7 @@ impl Type { pub fn replace_named_generics_with_type_variables(&mut self) { match self { Type::FieldElement - | Type::Constant(_) + | Type::Constant(_, _) | Type::Integer(_, _) | Type::Bool | Type::Unit @@ -2345,7 +2303,7 @@ impl From<&Type> for PrintableType { Type::FmtString(_, _) => unreachable!("format strings cannot be printed"), Type::Error => unreachable!(), Type::Unit => PrintableType::Unit, - Type::Constant(_) => unreachable!(), + Type::Constant(_, _) => unreachable!(), Type::Struct(def, ref args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); @@ -2432,7 +2390,7 @@ impl std::fmt::Debug for Type { write!(f, "({} : {}){:?}", name, typ, binding) } }, - Type::Constant(x) => x.fmt(f), + Type::Constant(x, kind) => write!(f, "({}: {})", x, kind), Type::Forall(typevars, typ) => { let typevars = vecmap(typevars, |var| format!("{:?}", var)); write!(f, "forall {}. {:?}", typevars.join(" "), typ) @@ -2537,7 +2495,7 @@ impl std::hash::Hash for Type { vars.hash(state); typ.hash(state); } - Type::Constant(value) => value.hash(state), + Type::Constant(value, _) => value.hash(state), Type::Quoted(typ) => typ.hash(state), Type::InfixExpr(lhs, op, rhs) => { lhs.hash(state); @@ -2597,7 +2555,9 @@ impl PartialEq for Type { (Forall(lhs_vars, lhs_type), Forall(rhs_vars, rhs_type)) => { lhs_vars == rhs_vars && lhs_type == rhs_type } - (Constant(lhs), Constant(rhs)) => lhs == rhs, + (Constant(lhs, lhs_kind), Constant(rhs, rhs_kind)) => { + lhs == rhs && lhs_kind == rhs_kind + } (Quoted(lhs), Quoted(rhs)) => lhs == rhs, (InfixExpr(l_lhs, l_op, l_rhs), InfixExpr(r_lhs, r_op, r_rhs)) => { l_lhs == r_lhs && l_op == r_op && l_rhs == r_rhs diff --git a/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs b/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs index 8c177615ec6..54b4c27a1f3 100644 --- a/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs +++ b/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs @@ -17,9 +17,11 @@ impl Type { Type::InfixExpr(lhs, op, rhs) => { // evaluate_to_u32 also calls canonicalize so if we just called // `self.evaluate_to_u32()` we'd get infinite recursion. - if let (Some(lhs), Some(rhs)) = (lhs.evaluate_to_u32(), rhs.evaluate_to_u32()) { - if let Some(result) = op.function(lhs, rhs) { - return Type::Constant(result); + if let (Some(lhs_u32), Some(rhs_u32)) = + (lhs.evaluate_to_u32(), rhs.evaluate_to_u32()) + { + if let Some(result) = op.function(lhs_u32, rhs_u32) { + return Type::Constant(result, lhs.infix_kind(&rhs)); } } @@ -65,11 +67,12 @@ impl Type { queue.push(*lhs); queue.push(*rhs); } - Type::Constant(new_constant) => { + Type::Constant(new_constant, new_constant_kind) => { if let Some(result) = op.function(constant, new_constant) { constant = result; } else { - *sorted.entry(Type::Constant(new_constant)).or_default() += 1; + let constant = Type::Constant(new_constant, new_constant_kind); + *sorted.entry(constant).or_default() += 1; } } other => { @@ -93,13 +96,14 @@ impl Type { } if constant != zero_value { - typ = Type::InfixExpr(Box::new(typ), op, Box::new(Type::Constant(constant))); + let constant = Type::Constant(constant, lhs.infix_kind(rhs)); + typ = Type::InfixExpr(Box::new(typ), op, Box::new(constant)); } typ } else { // Every type must have been a constant - Type::Constant(constant) + Type::Constant(constant, lhs.infix_kind(rhs)) } } @@ -202,7 +206,8 @@ impl Type { op = op.inverse()?; } let result = op.function(l_const, r_const)?; - Some(Type::InfixExpr(l_type, l_op, Box::new(Type::Constant(result)))) + let constant = Type::Constant(result, lhs.infix_kind(rhs)); + Some(Type::InfixExpr(l_type, l_op, Box::new(constant))) } (Multiplication | Division, Multiplication | Division) => { // If l_op is a division we want to inverse the rhs operator. @@ -214,7 +219,8 @@ impl Type { None } else { let result = op.function(l_const, r_const)?; - Some(Type::InfixExpr(l_type, l_op, Box::new(Type::Constant(result)))) + let constant = Box::new(Type::Constant(result, lhs.infix_kind(rhs))); + Some(Type::InfixExpr(l_type, l_op, constant)) } } _ => None, @@ -230,8 +236,8 @@ impl Type { ) -> Result<(), UnificationError> { if let Type::InfixExpr(lhs_a, op_a, rhs_a) = self { if let Some(inverse) = op_a.inverse() { - if let Some(rhs_a) = rhs_a.evaluate_to_u32() { - let rhs_a = Box::new(Type::Constant(rhs_a)); + if let Some(rhs_a_u32) = rhs_a.evaluate_to_u32() { + let rhs_a = Box::new(Type::Constant(rhs_a_u32, lhs_a.infix_kind(rhs_a))); let new_other = Type::InfixExpr(Box::new(other.clone()), inverse, rhs_a); let mut tmp_bindings = bindings.clone(); @@ -245,8 +251,8 @@ impl Type { if let Type::InfixExpr(lhs_b, op_b, rhs_b) = other { if let Some(inverse) = op_b.inverse() { - if let Some(rhs_b) = rhs_b.evaluate_to_u32() { - let rhs_b = Box::new(Type::Constant(rhs_b)); + if let Some(rhs_b_u32) = rhs_b.evaluate_to_u32() { + let rhs_b = Box::new(Type::Constant(rhs_b_u32, lhs_b.infix_kind(rhs_b))); let new_self = Type::InfixExpr(Box::new(self.clone()), inverse, rhs_b); let mut tmp_bindings = bindings.clone(); diff --git a/compiler/noirc_frontend/src/monomorphization/errors.rs b/compiler/noirc_frontend/src/monomorphization/errors.rs index 7f4172017e2..7c20328e798 100644 --- a/compiler/noirc_frontend/src/monomorphization/errors.rs +++ b/compiler/noirc_frontend/src/monomorphization/errors.rs @@ -5,6 +5,7 @@ use crate::{hir::comptime::InterpreterError, Type}; #[derive(Debug)] pub enum MonomorphizationError { UnknownArrayLength { length: Type, location: Location }, + UnknownConstant { location: Location }, NoDefaultType { location: Location }, InternalError { message: &'static str, location: Location }, InterpreterError(InterpreterError), @@ -16,6 +17,7 @@ impl MonomorphizationError { fn location(&self) -> Location { match self { MonomorphizationError::UnknownArrayLength { location, .. } + | MonomorphizationError::UnknownConstant { location } | MonomorphizationError::InternalError { location, .. } | MonomorphizationError::ComptimeFnInRuntimeCode { location, .. } | MonomorphizationError::ComptimeTypeInRuntimeCode { location, .. } @@ -40,6 +42,9 @@ impl MonomorphizationError { MonomorphizationError::UnknownArrayLength { length, .. } => { format!("Could not determine array length `{length}`") } + MonomorphizationError::UnknownConstant { .. } => { + "Could not resolve constant".to_string() + } MonomorphizationError::NoDefaultType { location } => { let message = "Type annotation needed".into(); let secondary = "Could not determine type of generic argument".into(); diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index fd06a2b04a8..12cc3b55b1f 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -1049,7 +1049,7 @@ impl<'interner> Monomorphizer<'interner> { ast::Type::MutableReference(Box::new(element)) } - HirType::Forall(_, _) | HirType::Constant(_) | HirType::InfixExpr(..) => { + HirType::Forall(_, _) | HirType::Constant(..) | HirType::InfixExpr(..) => { unreachable!("Unexpected type {typ} found") } HirType::Error => { @@ -1073,9 +1073,15 @@ impl<'interner> Monomorphizer<'interner> { | HirType::Unit | HirType::TraitAsType(..) | HirType::Forall(_, _) - | HirType::Constant(_) | HirType::Error | HirType::Quoted(_) => Ok(()), + HirType::Constant(_value, kind) => { + if kind.is_error() { + Err(MonomorphizationError::UnknownConstant { location }) + } else { + Ok(()) + } + } HirType::FmtString(_size, fields) => Self::check_type(fields.as_ref(), location), HirType::Array(_length, element) => Self::check_type(element.as_ref(), location), HirType::Slice(element) => Self::check_type(element.as_ref(), location), diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index f298559e65c..065e33608ba 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -2321,7 +2321,7 @@ fn get_type_method_key(typ: &Type) -> Option { // We do not support adding methods to these types Type::TypeVariable(_, _) | Type::Forall(_, _) - | Type::Constant(_) + | Type::Constant(..) | Type::Error | Type::Struct(_, _) | Type::InfixExpr(..) diff --git a/compiler/noirc_frontend/src/parser/parser.rs:28:9 b/compiler/noirc_frontend/src/parser/parser.rs:28:9 deleted file mode 100644 index 47dfb32b53b..00000000000 --- a/compiler/noirc_frontend/src/parser/parser.rs:28:9 +++ /dev/null @@ -1,45 +0,0 @@ -[?1049h[?1h[?2004h[?2026$p[?u[?12h[?25h[?25l(B[38:2:235:219:178m[48:2:168:153:132m [No Name]  (B[38:2:168:153:132m(B[38:2:235:219:178m (B[38:2:80:73:69m(B[38:2:168:153:132m[48:2:80:73:69m buffers -(B[38:2:124:111:100m 1 (B[38:2:235:219:178m -(B[38:2:80:73:69m~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -~ -(B[38:2:235:219:178m[48:2:168:153:132m (B[38:2:235:219:178m[48:2:168:153:132mNORMAL(B[38:2:235:219:178m[48:2:168:153:132m (B[38:2:168:153:132m[48:2:80:73:69m  jf/quoted-as-type (B[38:2:80:73:69m[48:2:60:56:54m(B[38:2:168:153:132m[48:2:60:56:54m (B[38:2:60:56:54m[48:2:60:56:54m(B[38:2:168:153:132m[48:2:60:56:54m  (B[38:2:80:73:69m[48:2:60:56:54m(B[38:2:168:153:132m[48:2:80:73:69m(B[38:2:235:219:178m[48:2:168:153:132m 100% (B[38:2:235:219:178m[48:2:168:153:132m☰ 0/1 (B[38:2:235:219:178m[48:2:168:153:132m : 1 (B[38:2:254:128:25m[48:2:168:153:132m(B[38:2:235:219:178mNVIM v0.10.0Nvim is open source and freely distributablehttps://neovim.io/#chattype :help nvim(B[38:2:80:73:69m(B[38:2:235:219:178m if you are new! type :checkhealth(B[38:2:80:73:69m(B[38:2:235:219:178m to optimize Nvimtype :q(B[38:2:80:73:69m(B[38:2:235:219:178m to exit type :help(B[38:2:80:73:69m(B[38:2:235:219:178m for help type :help news(B[38:2:80:73:69m(B[38:2:235:219:178m to see changes in v0.10Help poor children in Uganda!type :help iccf(B[38:2:80:73:69m(B[38:2:235:219:178m for information ]112[2 q]112[2 q[?1002h[?1006h(B[38:2:235:219:178m[48:2:168:153:132m [No Name]  (B[38:2:168:153:132m(B[38:2:235:219:178m (B[38:2:80:73:69m(B[38:2:168:153:132m[48:2:80:73:69m buffers -(B[38:2:124:111:100m 1 (B[38:2:235:219:178m -(B[38:2:80:73:69m~ -~ -~ (B[38:2:235:219:178mNVIM v0.10.0(B[38:2:80:73:69m -~ -~ (B[38:2:235:219:178mNvim is open source and freely distributable(B[38:2:80:73:69m -~ (B[38:2:235:219:178mhttps://neovim.io/#chat(B[38:2:80:73:69m -~ -~ (B[38:2:235:219:178mtype :help nvim(B[38:2:80:73:69m(B[38:2:235:219:178m if you are new! (B[38:2:80:73:69m -~ (B[38:2:235:219:178mtype :checkhealth(B[38:2:80:73:69m(B[38:2:235:219:178m to optimize Nvim(B[38:2:80:73:69m -~ (B[38:2:235:219:178mtype :q(B[38:2:80:73:69m(B[38:2:235:219:178m to exit (B[38:2:80:73:69m -~ (B[38:2:235:219:178mtype :help(B[38:2:80:73:69m(B[38:2:235:219:178m for help (B[38:2:80:73:69m -~ -~ (B[38:2:235:219:178mtype :help news(B[38:2:80:73:69m(B[38:2:235:219:178m to see changes in v0.10(B[38:2:80:73:69m -~ -~ (B[38:2:235:219:178mHelp poor children in Uganda!(B[38:2:80:73:69m -~ (B[38:2:235:219:178mtype :help iccf(B[38:2:80:73:69m(B[38:2:235:219:178m for information (B[38:2:80:73:69m -~ -~ -~ -~ -(B[38:2:235:219:178m[48:2:168:153:132m (B[38:2:235:219:178m[48:2:168:153:132mNORMAL(B[38:2:235:219:178m[48:2:168:153:132m (B[38:2:168:153:132m[48:2:80:73:69m  jf/quoted-as-type (B[38:2:80:73:69m[48:2:60:56:54m(B[38:2:168:153:132m[48:2:60:56:54m (B[38:2:60:56:54m[48:2:60:56:54m(B[38:2:168:153:132m[48:2:60:56:54m  (B[38:2:80:73:69m[48:2:60:56:54m(B[38:2:168:153:132m[48:2:80:73:69m(B[38:2:235:219:178m[48:2:168:153:132m 100% (B[38:2:235:219:178m[48:2:168:153:132m☰ 0/1 (B[38:2:235:219:178m[48:2:168:153:132m : 1 (B[38:2:254:128:25m[48:2:168:153:132m(B[38:2:235:219:178m[?12h[?25h[?25l[?1004h[?12h[?25h \ No newline at end of file diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index fb7aaeb847b..44e1cce5bf8 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -14,6 +14,7 @@ use fm::FileId; use iter_extended::vecmap; use noirc_errors::Location; +use crate::ast::IntegerBitSize; use crate::hir::comptime::InterpreterError; use crate::hir::def_collector::dc_crate::CompilationError; use crate::hir::def_collector::errors::{DefCollectorErrorKind, DuplicateType}; @@ -1296,8 +1297,8 @@ fn type_aliases_in_entry_point() { #[test] fn operators_in_global_used_in_type() { let src = r#" - global ONE = 1; - global COUNT = ONE + 2; + global ONE: u32 = 1; + global COUNT: u32 = ONE + 2; fn main() { let _array: [Field; COUNT] = [1, 2, 3]; } @@ -1337,7 +1338,7 @@ fn break_and_continue_outside_loop() { #[test] fn for_loop_over_array() { let src = r#" - fn hello(_array: [u1; N]) { + fn hello(_array: [u1; N]) { for _ in 0..N {} } @@ -1347,12 +1348,7 @@ fn for_loop_over_array() { } "#; let errors = get_program_errors(src); - assert_eq!(get_program_errors(src).len(), 1); - - assert!(matches!( - errors[0].0, - CompilationError::ResolverError(ResolverError::UseExplicitNumericGeneric { .. }) - )); + assert_eq!(errors.len(), 0); } // Regression for #4545 @@ -1656,7 +1652,7 @@ fn numeric_generic_in_function_signature() { } #[test] -fn numeric_generic_as_struct_field_type() { +fn numeric_generic_as_struct_field_type_fails() { let src = r#" pub struct Foo { a: Field, @@ -1667,7 +1663,7 @@ fn numeric_generic_as_struct_field_type() { assert_eq!(errors.len(), 1); assert!(matches!( errors[0].0, - CompilationError::ResolverError(ResolverError::NumericGenericUsedForType { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); } @@ -1681,11 +1677,9 @@ fn normal_generic_as_array_length() { "#; let errors = get_program_errors(src); assert_eq!(errors.len(), 1); - // TODO(https://github.com/noir-lang/noir/issues/5156): This should be switched to a hard type error rather than - // the `UseExplicitNumericGeneric` once implicit numeric generics are removed. assert!(matches!( errors[0].0, - CompilationError::ResolverError(ResolverError::UseExplicitNumericGeneric { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); } @@ -1699,31 +1693,32 @@ fn numeric_generic_as_param_type() { "#; let errors = get_program_errors(src); assert_eq!(errors.len(), 3); + // Error from the parameter type assert!(matches!( errors[0].0, - CompilationError::ResolverError(ResolverError::NumericGenericUsedForType { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); // Error from the let statement annotated type assert!(matches!( errors[1].0, - CompilationError::ResolverError(ResolverError::NumericGenericUsedForType { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); // Error from the return type assert!(matches!( errors[2].0, - CompilationError::ResolverError(ResolverError::NumericGenericUsedForType { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); } #[test] -fn numeric_generic_used_in_nested_type_fail() { +fn numeric_generic_used_in_nested_type_fails() { let src = r#" pub struct Foo { a: Field, b: Bar, } - pub struct Bar { + struct Bar { inner: N } "#; @@ -1731,7 +1726,7 @@ fn numeric_generic_used_in_nested_type_fail() { assert_eq!(errors.len(), 1); assert!(matches!( errors[0].0, - CompilationError::ResolverError(ResolverError::NumericGenericUsedForType { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); } @@ -1747,8 +1742,11 @@ fn normal_generic_used_in_nested_array_length_fail() { } "#; let errors = get_program_errors(src); - // TODO(https://github.com/noir-lang/noir/issues/5156): This should be switched to a hard type error once implicit numeric generics are removed. - assert_eq!(errors.len(), 0); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), + )); } #[test] @@ -1894,7 +1892,7 @@ fn normal_generic_used_when_numeric_expected_in_where_clause() { assert_eq!(errors.len(), 1); assert!(matches!( errors[0].0, - CompilationError::TypeError(TypeCheckError::TypeMismatch { .. }), + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), )); let src = r#" @@ -1911,26 +1909,65 @@ fn normal_generic_used_when_numeric_expected_in_where_clause() { } "#; let errors = get_program_errors(src); - assert_eq!(errors.len(), 1); + assert_eq!(errors.len(), 4); assert!(matches!( errors[0].0, + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), + )); + assert!(matches!( + errors[1].0, + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), + )); + assert!(matches!( + errors[2].0, + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), + )); + // N + assert!(matches!( + errors[3].0, CompilationError::ResolverError(ResolverError::VariableNotDeclared { .. }), )); } -// TODO(https://github.com/noir-lang/noir/issues/5156): Remove this test once we ban implicit numeric generics #[test] -fn implicit_numeric_generics_elaborator() { +fn numeric_generics_type_kind_mismatch() { let src = r#" - struct BoundedVec { + fn foo() -> u16 { + N as u16 + } + + global J: u16 = 10; + + fn bar() -> u16 { + foo::() + } + + global M: u16 = 3; + + fn main() { + let _ = bar::(); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::TypeError(TypeCheckError::TypeKindMismatch { .. }), + )); +} + +#[test] +fn numeric_generics_value_kind_mismatch_u32_u64() { + let src = r#" + struct BoundedVec { storage: [T; MaxLen], + // can't be compared to MaxLen: u32 + // can't be used to index self.storage len: u64, } - - impl BoundedVec { - // Test that we have an implicit numeric generic for "Len" as well as "MaxLen" - pub fn extend_from_bounded_vec(&mut self, _vec: BoundedVec) { + impl BoundedVec { + pub fn extend_from_bounded_vec(&mut self, _vec: BoundedVec) { // We do this to avoid an unused variable warning on `self` let _ = self.len; for _ in 0..Len { } @@ -1944,17 +1981,15 @@ fn implicit_numeric_generics_elaborator() { } "#; let errors = get_program_errors(src); - assert_eq!(errors.len(), 4); - - for error in errors.iter() { - if let CompilationError::ResolverError(ResolverError::UseExplicitNumericGeneric { ident }) = - &errors[0].0 - { - assert!(matches!(ident.0.contents.as_str(), "MaxLen" | "Len")); - } else { - panic!("Expected ResolverError::UseExplicitNumericGeneric but got {:?}", error); - } - } + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::TypeError(TypeCheckError::IntegerBitWidth { + bit_width_x: IntegerBitSize::SixtyFour, + bit_width_y: IntegerBitSize::ThirtyTwo, + .. + }), + )); } #[test] diff --git a/docs/docs/noir/concepts/data_types/slices.mdx b/docs/docs/noir/concepts/data_types/slices.mdx index a0c87c29259..cfee564a302 100644 --- a/docs/docs/noir/concepts/data_types/slices.mdx +++ b/docs/docs/noir/concepts/data_types/slices.mdx @@ -175,7 +175,7 @@ Make sure to specify the size of the resulting array. Panics if the resulting array length is different than the slice's length. ```rust -fn as_array(self) -> [T; N] +fn as_array(self) -> [T; N] ``` Example: diff --git a/docs/docs/noir/concepts/generics.md b/docs/docs/noir/concepts/generics.md index 6dbde4ed53b..8925666aa20 100644 --- a/docs/docs/noir/concepts/generics.md +++ b/docs/docs/noir/concepts/generics.md @@ -18,6 +18,32 @@ fn id(x: T) -> T { } ``` +## Numeric Generics + +If we want to be generic over array lengths (which are type-level integers), we can use numeric +generics. Using these looks similar to using regular generics, but introducing them into scope +requires declaring them with `let MyGenericName: IntegerType`. This can be done anywhere a normal +generic is declared. Instead of types, these generics resolve to integers at compile-time. +Here's an example of a struct that is generic over the size of the array it contains internally: + +```rust +struct BigInt { + limbs: [u32; N], +} + +impl BigInt { + // `N` is in scope of all methods in the impl + fn first(first: BigInt, second: BigInt) -> Self { + assert(first.limbs != second.limbs); + first + + fn second(first: BigInt, second: Self) -> Self { + assert(first.limbs != second.limbs); + second + } +} +``` + ## In Structs Generics are useful for specifying types in structs. For example, we can specify that a field in a @@ -45,32 +71,6 @@ fn main() { The `print` function will print `Hello!` an arbitrary number of times, twice in this case. -## Numeric Generics - -If we want to be generic over array lengths (which are type-level integers), we can use numeric -generics. Using these looks similar to using regular generics, but introducing them into scope -requires declaring them with `let MyGenericName: IntegerType`. This can be done anywhere a normal -generic is declared. Instead of types, these generics resolve to integers at compile-time. -Here's an example of a struct that is generic over the size of the array it contains internally: - -```rust -struct BigInt { - limbs: [u32; N], -} - -impl BigInt { - // `N` is in scope of all methods in the impl - fn first(first: BigInt, second: BigInt) -> Self { - assert(first.limbs != second.limbs); - first - - fn second(first: BigInt, second: Self) -> Self { - assert(first.limbs != second.limbs); - second - } -} -``` - ## Calling functions on generic parameters Since a generic type `T` can represent any type, how can we call functions on the underlying type? @@ -125,15 +125,8 @@ fn main() { let array = slice.as_array::<2>(); } ``` -```rust -fn double() -> u32 { - N * 2 -} -fn example() { - assert(double::<9>() == 18); - assert(double::<7 + 8>() == 30); -} -``` + + ```rust trait MyTrait { fn ten() -> Self; diff --git a/docs/docs/noir/concepts/globals.md b/docs/docs/noir/concepts/globals.md index 063a3d89248..97a92a86e72 100644 --- a/docs/docs/noir/concepts/globals.md +++ b/docs/docs/noir/concepts/globals.md @@ -37,7 +37,7 @@ global T = foo(T); // dependency error If they are initialized to a literal integer, globals can be used to specify an array's length: ```rust -global N: Field = 2; +global N: u32 = 2; fn main(y : [Field; N]) { assert(y[0] == y[1]) diff --git a/docs/docs/noir/concepts/traits.md b/docs/docs/noir/concepts/traits.md index b07d2cf3a08..5d07e0c68f0 100644 --- a/docs/docs/noir/concepts/traits.md +++ b/docs/docs/noir/concepts/traits.md @@ -153,7 +153,7 @@ will implement `Foo` only for types that also implement `Bar`. This is often use For example, here is the implementation for array equality: ```rust -impl Eq for [T; N] where T: Eq { +impl Eq for [T; let N: u32] where T: Eq { // Test if two arrays have the same elements. // Because both arrays must have length N, we know their lengths already match. fn eq(self, other: Self) -> bool { diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx index 6ff47a77df9..d2a8204bccb 100644 --- a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -144,7 +144,7 @@ fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field otherwise, use the `mimc_bn254` method: ```rust -fn mimc_bn254(array: [Field; N]) -> Field +fn mimc_bn254(array: [Field; N]) -> Field ``` example: diff --git a/noir_stdlib/src/hash/keccak.nr b/noir_stdlib/src/hash/keccak.nr index 36787c7b4af..c3321b62693 100644 --- a/noir_stdlib/src/hash/keccak.nr +++ b/noir_stdlib/src/hash/keccak.nr @@ -2,7 +2,7 @@ use crate::collections::vec::Vec; use crate::runtime::is_unconstrained; global LIMBS_PER_BLOCK = 17; //BLOCK_SIZE / 8; -global NUM_KECCAK_LANES = 25; +global NUM_KECCAK_LANES: u32 = 25; global BLOCK_SIZE = 136; //(1600 - BITS * 2) / WORD_SIZE; global WORD_SIZE = 8; @@ -77,7 +77,7 @@ pub(crate) fn keccak256(input: [u8; N], message_size: u32) -> [u8; 3 } //2. sponge_absorb - let mut state : [u64;NUM_KECCAK_LANES]= [0; NUM_KECCAK_LANES]; + let mut state : [u64; NUM_KECCAK_LANES]= [0; NUM_KECCAK_LANES]; // When in an unconstrained runtime we can take advantage of runtime loop bounds, // thus allowing us to simplify the loop body. if is_unconstrained() { diff --git a/noir_stdlib/src/hash/mimc.nr b/noir_stdlib/src/hash/mimc.nr index 2b5af6cc68a..8c43536d18b 100644 --- a/noir_stdlib/src/hash/mimc.nr +++ b/noir_stdlib/src/hash/mimc.nr @@ -18,7 +18,7 @@ fn mimc(x: Field, k: Field, constants: [Field; N], exp: Field) -> Fi h + k } -global MIMC_BN254_ROUNDS = 91; +global MIMC_BN254_ROUNDS: u32 = 91; //generated from seed "mimc" using keccak256 global MIMC_BN254_CONSTANTS: [Field; MIMC_BN254_ROUNDS] = [ 0, diff --git a/test_programs/compile_success_empty/closure_explicit_types/src/main.nr b/test_programs/compile_success_empty/closure_explicit_types/src/main.nr index b6c8a6b7b3c..c43fc9cb34b 100644 --- a/test_programs/compile_success_empty/closure_explicit_types/src/main.nr +++ b/test_programs/compile_success_empty/closure_explicit_types/src/main.nr @@ -35,7 +35,7 @@ fn add_results(f1: fn[Env1]() -> Field, f2: fn[Env2]() -> Field) -> f1() + f2() } // a *really* generic function -fn map(arr: [T; N], f: fn[Env](T) -> U) -> [U; N] { +fn map(arr: [T; N], f: fn[Env](T) -> U) -> [U; N] { let first_elem = f(arr[0]); let mut ret = [first_elem; N]; diff --git a/test_programs/compile_success_empty/macros_in_comptime/src/main.nr b/test_programs/compile_success_empty/macros_in_comptime/src/main.nr index c5cc7880112..197f4e87f0b 100644 --- a/test_programs/compile_success_empty/macros_in_comptime/src/main.nr +++ b/test_programs/compile_success_empty/macros_in_comptime/src/main.nr @@ -1,11 +1,14 @@ use std::field::modulus_num_bits; use std::meta::unquote; +// Numeric generics default to u32 +global three_field: Field = 3; + fn main() { comptime { unsafe { - foo::<3>(5) + foo::(5) }; submodule::bar(); } diff --git a/test_programs/compile_success_empty/numeric_generics/src/main.nr b/test_programs/compile_success_empty/numeric_generics/src/main.nr index 340c18c2a1d..04f170aef58 100644 --- a/test_programs/compile_success_empty/numeric_generics/src/main.nr +++ b/test_programs/compile_success_empty/numeric_generics/src/main.nr @@ -14,15 +14,15 @@ fn main() { assert(foo(itWorks2).data[0] == itWorks2.data[0] + 1); } -fn id(x: [Field; I]) -> [Field; I] { +fn id(x: [Field; I]) -> [Field; I] { x } -struct MyStruct { +struct MyStruct { data: [Field; S], } -impl MyStruct { +impl MyStruct { fn insert(mut self: Self, index: Field, elem: Field) -> Self { // Regression test for numeric generics on impls assert(index as u64 < S as u64); diff --git a/test_programs/compile_success_empty/regression_4635/src/main.nr b/test_programs/compile_success_empty/regression_4635/src/main.nr index 6709a421470..6bccdf9e30f 100644 --- a/test_programs/compile_success_empty/regression_4635/src/main.nr +++ b/test_programs/compile_success_empty/regression_4635/src/main.nr @@ -12,7 +12,7 @@ trait Deserialize { fn deserialize(fields: [Field; N]) -> Self; } -global AZTEC_ADDRESS_LENGTH = 1; +global AZTEC_ADDRESS_LENGTH: u32 = 1; struct AztecAddress { inner : Field diff --git a/test_programs/compile_success_empty/serialize/src/main.nr b/test_programs/compile_success_empty/serialize/src/main.nr index 6fee6fb72a6..19f3f0319b8 100644 --- a/test_programs/compile_success_empty/serialize/src/main.nr +++ b/test_programs/compile_success_empty/serialize/src/main.nr @@ -7,7 +7,7 @@ trait Serialize { impl Serialize for (A, B) where A: Serialize, B: Serialize { // let Size = ::Size + ::Size; - let Size = AS + BS; + let Size: u32 = AS + BS; fn serialize(self: Self) -> [Field; Self::Size] { let mut array: [Field; Self::Size] = std::mem::zeroed(); @@ -26,7 +26,7 @@ impl Serialize for (A, B) where A: Serialize Serialize for [T; N] where T: Serialize { // let Size = ::Size * N; - let Size = TS * N; + let Size: u32 = TS * N; fn serialize(self: Self) -> [Field; Self::Size] { let mut array: [Field; Self::Size] = std::mem::zeroed(); @@ -46,7 +46,7 @@ impl Serialize for [T; N] where T: Serialize [Field; Self::Size] { [self] diff --git a/test_programs/compile_success_empty/trait_generics/src/main.nr b/test_programs/compile_success_empty/trait_generics/src/main.nr index 15591f2f2ea..77309ca4bee 100644 --- a/test_programs/compile_success_empty/trait_generics/src/main.nr +++ b/test_programs/compile_success_empty/trait_generics/src/main.nr @@ -44,13 +44,13 @@ impl Serializable<2> for Data { } } -fn sum(data: T) -> Field where T: Serializable { +fn sum(data: T) -> Field where T: Serializable { let serialized = data.serialize(); serialized.fold(0, |acc, elem| acc + elem) } // Test static trait method syntax -fn sum_static(data: T) -> Field where T: Serializable { +fn sum_static(data: T) -> Field where T: Serializable { let serialized = Serializable::serialize(data); serialized.fold(0, |acc, elem| acc + elem) } diff --git a/test_programs/execution_success/7_function/src/main.nr b/test_programs/execution_success/7_function/src/main.nr index dc56f2bea4f..32227b841bd 100644 --- a/test_programs/execution_success/7_function/src/main.nr +++ b/test_programs/execution_success/7_function/src/main.nr @@ -82,7 +82,7 @@ fn test_multiple6(a: my2, b: my_struct, c: (my2, my_struct)) { assert(c.0.aa.a == c.1.a); } -fn foo(a: [Field; N]) -> [Field; N] { +fn foo(a: [Field; N]) -> [Field; N] { a } diff --git a/test_programs/execution_success/aes128_encrypt/src/main.nr b/test_programs/execution_success/aes128_encrypt/src/main.nr index 9cf07841b9e..b937c801860 100644 --- a/test_programs/execution_success/aes128_encrypt/src/main.nr +++ b/test_programs/execution_success/aes128_encrypt/src/main.nr @@ -8,7 +8,7 @@ unconstrained fn decode_ascii(ascii: u8) -> u8 { } } -unconstrained fn decode_hex(s: str) -> [u8; M] { +unconstrained fn decode_hex(s: str) -> [u8; M] { let mut result: [u8; M] = [0; M]; let as_bytes = s.as_bytes(); for i in 0..N { diff --git a/test_programs/execution_success/array_len/src/main.nr b/test_programs/execution_success/array_len/src/main.nr index 126fcd18d3f..d794690711a 100644 --- a/test_programs/execution_success/array_len/src/main.nr +++ b/test_programs/execution_success/array_len/src/main.nr @@ -1,12 +1,12 @@ -fn len_plus_1(array: [T; N]) -> u32 { +fn len_plus_1(array: [T; N]) -> u32 { array.len() + 1 } -fn add_lens(a: [T; N], b: [Field; M]) -> u32 { +fn add_lens(a: [T; N], b: [Field; M]) -> u32 { a.len() + b.len() } -fn nested_call(b: [Field; N]) -> u32 { +fn nested_call(b: [Field; N]) -> u32 { len_plus_1(b) } diff --git a/test_programs/execution_success/array_to_slice/src/main.nr b/test_programs/execution_success/array_to_slice/src/main.nr index 0d0f9562d7b..3ca8bfff2ae 100644 --- a/test_programs/execution_success/array_to_slice/src/main.nr +++ b/test_programs/execution_success/array_to_slice/src/main.nr @@ -1,5 +1,5 @@ // Converts an array into a slice. -fn as_slice_push(xs: [T; N]) -> [T] { +fn as_slice_push(xs: [T; N]) -> [T] { let mut slice = &[]; for elem in xs { slice = slice.push_back(elem); diff --git a/test_programs/execution_success/brillig_cow_regression/src/main.nr b/test_programs/execution_success/brillig_cow_regression/src/main.nr index adeadfc9f20..3fce7fb2c7d 100644 --- a/test_programs/execution_success/brillig_cow_regression/src/main.nr +++ b/test_programs/execution_success/brillig_cow_regression/src/main.nr @@ -1,16 +1,16 @@ // Tests a performance regression found in aztec-packages with brillig cow optimization -global MAX_NOTE_HASHES_PER_TX: u64 = 64; -global MAX_NULLIFIERS_PER_TX: u64 = 64; -global MAX_L2_TO_L1_MSGS_PER_TX: u64 = 2; -global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u64 = 16; -global MAX_NEW_CONTRACTS_PER_TX: u64 = 1; -global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; -global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; -global NUM_FIELDS_PER_SHA256 = 2; +global MAX_NOTE_HASHES_PER_TX: u32 = 64; +global MAX_NULLIFIERS_PER_TX: u32 = 64; +global MAX_L2_TO_L1_MSGS_PER_TX: u32 = 2; +global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u32 = 16; +global MAX_NEW_CONTRACTS_PER_TX: u32 = 1; +global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: u32 = 1; +global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: u32 = 1; +global NUM_FIELDS_PER_SHA256: u32 = 2; global TX_EFFECT_HASH_INPUT_SIZE = 169; -global TX_EFFECT_HASH_LOG_FIELDS = 4; -global TX_EFFECT_HASH_FULL_FIELDS = 165; +global TX_EFFECT_HASH_LOG_FIELDS: u32 = 4; +global TX_EFFECT_HASH_FULL_FIELDS: u32 = 165; struct PublicDataUpdateRequest { leaf_slot : Field, diff --git a/test_programs/execution_success/brillig_keccak/src/main.nr b/test_programs/execution_success/brillig_keccak/src/main.nr index dd339208659..9674ed92942 100644 --- a/test_programs/execution_success/brillig_keccak/src/main.nr +++ b/test_programs/execution_success/brillig_keccak/src/main.nr @@ -21,6 +21,6 @@ fn main(x: Field, result: [u8; 32]) { } } -unconstrained fn keccak256(data: [u8; N], msg_len: u32) -> [u8; 32] { +unconstrained fn keccak256(data: [u8; N], msg_len: u32) -> [u8; 32] { std::hash::keccak256(data, msg_len) } diff --git a/test_programs/execution_success/cast_and_shift_global/src/main.nr b/test_programs/execution_success/cast_and_shift_global/src/main.nr index 577de78465c..2c0158fc71a 100644 --- a/test_programs/execution_success/cast_and_shift_global/src/main.nr +++ b/test_programs/execution_success/cast_and_shift_global/src/main.nr @@ -1,6 +1,6 @@ -global THREE: u64 = 3; -global EIGHT: u64 = 1 << THREE as u8; -global SEVEN: u64 = EIGHT - 1; +global THREE: u32 = 3; +global EIGHT: u32 = 1 << THREE as u8; +global SEVEN: u32 = EIGHT - 1; fn main() { assert([0; EIGHT] == [0; 8]); diff --git a/test_programs/execution_success/debug_logs/src/main.nr b/test_programs/execution_success/debug_logs/src/main.nr index c7fd01ebbc5..d1314406068 100644 --- a/test_programs/execution_success/debug_logs/src/main.nr +++ b/test_programs/execution_success/debug_logs/src/main.nr @@ -79,11 +79,11 @@ fn string_identity(string: fmtstr<14, (Field, Field)>) -> fmtstr<14, (Field, Fie string } -fn string_with_generics(string: fmtstr) -> fmtstr { +fn string_with_generics(string: fmtstr) -> fmtstr { string } -fn string_with_partial_generics(string: fmtstr) -> fmtstr { +fn string_with_partial_generics(string: fmtstr) -> fmtstr { string } diff --git a/test_programs/execution_success/fold_numeric_generic_poseidon/src/main.nr b/test_programs/execution_success/fold_numeric_generic_poseidon/src/main.nr index 8727b2a23de..8eaea086ec0 100644 --- a/test_programs/execution_success/fold_numeric_generic_poseidon/src/main.nr +++ b/test_programs/execution_success/fold_numeric_generic_poseidon/src/main.nr @@ -1,6 +1,6 @@ use std::hash::{pedersen_hash_with_separator, poseidon2::Poseidon2}; -global NUM_HASHES = 2; +global NUM_HASHES: u32 = 2; global HASH_LENGTH = 10; #[fold] diff --git a/test_programs/execution_success/generics/src/main.nr b/test_programs/execution_success/generics/src/main.nr index 75a7f8a3154..329759caea0 100644 --- a/test_programs/execution_success/generics/src/main.nr +++ b/test_programs/execution_success/generics/src/main.nr @@ -8,11 +8,11 @@ fn foo(bar: Bar) { assert(bar.one == bar.two); } -struct BigInt { +struct BigInt { limbs: [u32; N], } -impl BigInt { +impl BigInt { // `N` is in scope of all methods in the impl fn first(first: BigInt, second: BigInt) -> Self { assert(first.limbs != second.limbs); @@ -69,7 +69,7 @@ fn main(x: Field, y: Field) { let _ = regression_2055([1, 2, 3]); } -fn regression_2055(bytes: [u8; LEN]) -> Field { +fn regression_2055(bytes: [u8; LEN]) -> Field { let mut f = 0; let mut b = 1; let mut len = LEN - 1; // FAILS diff --git a/test_programs/execution_success/global_consts/src/foo.nr b/test_programs/execution_success/global_consts/src/foo.nr index 413b9c3a74b..50e331493dc 100644 --- a/test_programs/execution_success/global_consts/src/foo.nr +++ b/test_programs/execution_success/global_consts/src/foo.nr @@ -1,7 +1,7 @@ mod bar; -global N: u64 = 5; -global MAGIC_NUMBER: u64 = 3; +global N: u32 = 5; +global MAGIC_NUMBER: u32 = 3; global TYPE_INFERRED = 42; pub fn from_foo(x: [Field; bar::N]) { diff --git a/test_programs/execution_success/global_consts/src/foo/bar.nr b/test_programs/execution_success/global_consts/src/foo/bar.nr index 5404c9cf1e3..61ac1e8e8ed 100644 --- a/test_programs/execution_success/global_consts/src/foo/bar.nr +++ b/test_programs/execution_success/global_consts/src/foo/bar.nr @@ -1,4 +1,4 @@ -global N: u64 = 5; +global N: u32 = 5; pub fn from_bar(x: Field) -> Field { x * N as Field diff --git a/test_programs/execution_success/global_consts/src/main.nr b/test_programs/execution_success/global_consts/src/main.nr index 966be2741d6..0b382ff6b8b 100644 --- a/test_programs/execution_success/global_consts/src/main.nr +++ b/test_programs/execution_success/global_consts/src/main.nr @@ -1,13 +1,13 @@ mod foo; mod baz; -global M: Field = 32; +global M: u32 = 32; global L: Field = 10; // Unused globals currently allowed -global N: u64 = 5; -global T_LEN = 2; // Type inference is allowed on globals +global N: u32 = 5; +global T_LEN: u32 = 2; // Globals can reference other globals -global DERIVED = M + L; +global DERIVED: Field = M as Field + L; struct Dummy { x: [Field; N], @@ -41,7 +41,7 @@ fn main( assert(test_struct.y[i] != NESTED[1][0].v); } - assert(N as Field != M); + assert(N as Field != M as Field); let expected: u32 = 42; assert(foo::TYPE_INFERRED == expected); @@ -49,7 +49,7 @@ fn main( let mut y = 5; let mut x = M; for i in 0..N * N { - let M: Field = 10; + let M: u32 = 10; x = M; y = i; @@ -62,14 +62,14 @@ fn main( arrays_neq(a, b); - let t: [Field; T_LEN] = [N as Field, M]; + let t: [Field; T_LEN] = [N as Field, M as Field]; assert(t[1] == 32); assert(15 == my_submodule::my_helper()); - let add_submodules_N = my_submodule::N + foo::bar::N as Field; + let add_submodules_N = my_submodule::N as Field + foo::bar::N as Field; assert(15 == add_submodules_N); - let add_from_bar_N = my_submodule::N + foo::bar::from_bar(1); + let add_from_bar_N = my_submodule::N as Field + foo::bar::from_bar(1); assert(15 == add_from_bar_N); // Example showing an array filled with (my_submodule::N + 2) 0's let sugared = [0; my_submodule::N + 2]; @@ -80,13 +80,13 @@ fn main( foo::from_foo(d); baz::from_baz(c); - assert(DERIVED == M + L); + assert(DERIVED == M as Field + L); assert(CALCULATED_GLOBAL == 42); } fn multiplyByM(x: Field) -> Field { - x * M + x * M as Field } fn arrays_neq(a: [Field; M], b: [Field; M]) { @@ -94,7 +94,7 @@ fn arrays_neq(a: [Field; M], b: [Field; M]) { } mod my_submodule { - global N: Field = 10; + global N: u32 = 10; global L: Field = 50; fn my_bool_or(x: u1, y: u1) { @@ -102,8 +102,8 @@ mod my_submodule { } pub fn my_helper() -> Field { - let N: Field = 15; // Like in Rust, local variables override globals - let x = N; + let N: u32 = 15; // Like in Rust, local variables override globals + let x = N as Field; x } } diff --git a/test_programs/execution_success/hashmap/src/main.nr b/test_programs/execution_success/hashmap/src/main.nr index 56b13d6779b..e8bc486e1e2 100644 --- a/test_programs/execution_success/hashmap/src/main.nr +++ b/test_programs/execution_success/hashmap/src/main.nr @@ -15,7 +15,7 @@ struct Entry{ value: Field } -global HASHMAP_CAP = 8; +global HASHMAP_CAP: u32 = 8; global HASHMAP_LEN = 6; global FIELD_CMP = |a: Field, b: Field| a.lt(b); diff --git a/test_programs/execution_success/hashmap/src/utils.nr b/test_programs/execution_success/hashmap/src/utils.nr index ee73245a902..de6c78f5adf 100644 --- a/test_programs/execution_success/hashmap/src/utils.nr +++ b/test_programs/execution_success/hashmap/src/utils.nr @@ -1,5 +1,5 @@ // Compile-time: cuts the M first elements from the BoundedVec. -pub(crate) fn cut(input: BoundedVec) -> [T; M] { +pub(crate) fn cut(input: BoundedVec) -> [T; M] { assert(M < N, "M should be less than N."); let mut new = BoundedVec::new(); diff --git a/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr index 60a7d2f8d17..d6b463dbe30 100644 --- a/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr +++ b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr @@ -1,6 +1,6 @@ -use std::hash::{pedersen_hash_with_separator, poseidon2::Poseidon2}; +use std::hash::poseidon2::Poseidon2; -global NUM_HASHES = 2; +global NUM_HASHES: u32 = 2; global HASH_LENGTH = 10; #[no_predicates] diff --git a/test_programs/execution_success/regression/src/main.nr b/test_programs/execution_success/regression/src/main.nr index e60791aface..e6226de29ef 100644 --- a/test_programs/execution_success/regression/src/main.nr +++ b/test_programs/execution_success/regression/src/main.nr @@ -20,7 +20,7 @@ impl Eq for U4 { } } -fn compact_decode(input: [u8; N], length: Field) -> ([U4; NIBBLE_LENGTH], Field) { +fn compact_decode(input: [u8; N], length: Field) -> ([U4; NIBBLE_LENGTH], Field) { assert(2 * input.len() <= NIBBLE_LENGTH); assert(length as u32 <= input.len()); @@ -53,7 +53,7 @@ fn compact_decode(input: [u8; N], length: Field) -> ([U4; NIBBLE_LENGTH], Fie out } -fn enc(value: [u8; N], value_length: Field) -> ([u8; 32], Field) { +fn enc(value: [u8; N], value_length: Field) -> ([u8; 32], Field) { assert(value.len() as u8 >= value_length as u8); let mut out_value = [0; 32]; if value_length == 0 { diff --git a/test_programs/execution_success/regression_4088/src/main.nr b/test_programs/execution_success/regression_4088/src/main.nr index 12a7afca68c..b2a050b5db3 100644 --- a/test_programs/execution_success/regression_4088/src/main.nr +++ b/test_programs/execution_success/regression_4088/src/main.nr @@ -16,7 +16,7 @@ fn check(serialized_note: [Field; N]) { assert(serialized_note[0] == 0); } -fn oopsie(note: Note) where Note: Serialize { +fn oopsie(note: Note) where Note: Serialize { let serialized_note = Note::serialize(note); check(serialized_note) diff --git a/test_programs/execution_success/regression_4124/src/main.nr b/test_programs/execution_success/regression_4124/src/main.nr index 7b5060062da..b0e1a394c32 100644 --- a/test_programs/execution_success/regression_4124/src/main.nr +++ b/test_programs/execution_success/regression_4124/src/main.nr @@ -24,7 +24,7 @@ impl PublicMutable { PublicMutable { storage_slot } } - pub fn read(_self: Self) -> T where T: MyDeserialize { + pub fn read(_self: Self) -> T where T: MyDeserialize { // storage_read returns slice here let fields: [Field; T_SERIALIZED_LEN] = storage_read(); T::deserialize(fields) diff --git a/test_programs/execution_success/schnorr/src/main.nr b/test_programs/execution_success/schnorr/src/main.nr index 8b3b4735145..b64078e6b46 100644 --- a/test_programs/execution_success/schnorr/src/main.nr +++ b/test_programs/execution_success/schnorr/src/main.nr @@ -36,7 +36,11 @@ fn main( // Meanwhile, you have to use a message with 32 additional bytes: // If you want to verify a signature on a message of 10 bytes, you need to pass a message of length 42, // where the first 10 bytes are the one from the original message (the other bytes are not used) -pub fn verify_signature_noir(public_key: embedded_curve_ops::EmbeddedCurvePoint, signature: [u8; 64], message: [u8; M]) -> bool { +pub fn verify_signature_noir( + public_key: embedded_curve_ops::EmbeddedCurvePoint, + signature: [u8; 64], + message: [u8; M] +) -> bool { let N = message.len() - 32; //scalar lo/hi from bytes @@ -85,7 +89,11 @@ pub fn bytes_to_scalar(bytes: [u8; 64], offset: u32) -> embedded_curve_ops::Embe sig_s } -pub fn assert_valid_signature(public_key: embedded_curve_ops::EmbeddedCurvePoint, signature: [u8; 64], message: [u8; M]) { +pub fn assert_valid_signature( + public_key: embedded_curve_ops::EmbeddedCurvePoint, + signature: [u8; 64], + message: [u8; M] +) { let N = message.len() - 32; //scalar lo/hi from bytes let sig_s = bytes_to_scalar(signature, 0); diff --git a/test_programs/noir_test_success/bounded_vec/src/main.nr b/test_programs/noir_test_success/bounded_vec/src/main.nr index 7b3e63df072..cb9879b1c9e 100644 --- a/test_programs/noir_test_success/bounded_vec/src/main.nr +++ b/test_programs/noir_test_success/bounded_vec/src/main.nr @@ -52,7 +52,7 @@ fn test_vec_get_unchecked() { } // docs:start:get_unchecked_example -fn sum_of_first_three(v: BoundedVec) -> u32 { +fn sum_of_first_three(v: BoundedVec) -> u32 { // Always ensure the length is larger than the largest // index passed to get_unchecked assert(v.len() > 2); diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index a957d88fd3b..17652d37509 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -597,7 +597,7 @@ impl<'a> NodeFinder<'a> { | Type::TraitAsType(_, _, _) | Type::Function(..) | Type::Forall(_, _) - | Type::Constant(_) + | Type::Constant(..) | Type::Quoted(_) | Type::InfixExpr(_, _, _) | Type::Error => (), diff --git a/tooling/lsp/src/requests/hover.rs b/tooling/lsp/src/requests/hover.rs index 8e9666a624b..edc71e94b08 100644 --- a/tooling/lsp/src/requests/hover.rs +++ b/tooling/lsp/src/requests/hover.rs @@ -447,7 +447,7 @@ impl<'a> TypeLinksGatherer<'a> { | Type::FmtString(_, _) | Type::Unit | Type::Forall(_, _) - | Type::Constant(_) + | Type::Constant(..) | Type::Quoted(_) | Type::Error => (), } diff --git a/tooling/lsp/src/trait_impl_method_stub_generator.rs b/tooling/lsp/src/trait_impl_method_stub_generator.rs index f80bdf000b0..ae12bac4c06 100644 --- a/tooling/lsp/src/trait_impl_method_stub_generator.rs +++ b/tooling/lsp/src/trait_impl_method_stub_generator.rs @@ -373,7 +373,7 @@ impl<'a> TraitImplMethodStubGenerator<'a> { self.string.push(' '); self.append_type(right); } - Type::Constant(_) + Type::Constant(..) | Type::Integer(_, _) | Type::Bool | Type::String(_) diff --git a/tooling/noir_codegen/test/test_lib/src/lib.nr b/tooling/noir_codegen/test/test_lib/src/lib.nr index 4915b0a2c49..4229de06157 100644 --- a/tooling/noir_codegen/test/test_lib/src/lib.nr +++ b/tooling/noir_codegen/test/test_lib/src/lib.nr @@ -1,10 +1,10 @@ -struct MyStruct { +struct MyStruct { foo: bool, bar: [str; BAR_SIZE], baz: Field } -struct NestedStruct { +struct NestedStruct { foo: MyStruct, bar: [MyStruct; BAR_SIZE], baz: BAZ_TYP