From fc14483c9bc76772b1b6ffaf58d7d04545f730f0 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:30:02 -0300 Subject: [PATCH 01/11] Add `Type::is_unit` --- .../src/hir/comptime/interpreter/builtin.rs | 9 +++++++ docs/docs/noir/standard_library/meta/typ.md | 6 +++++ noir_stdlib/src/meta/typ.nr | 27 +++++++++++-------- .../comptime_type/src/main.nr | 4 +++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 166c6479b15..20c8265c200 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -185,6 +185,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "type_implements" => type_implements(interner, arguments, location), "type_is_bool" => type_is_bool(arguments, location), "type_is_field" => type_is_field(arguments, location), + "type_is_unit" => type_is_unit(arguments, location), "type_of" => type_of(arguments, location), "typed_expr_as_function_definition" => { typed_expr_as_function_definition(interner, arguments, return_type, location) @@ -969,6 +970,14 @@ fn type_is_field(arguments: Vec<(Value, Location)>, location: Location) -> IResu Ok(Value::Bool(matches!(typ, Type::FieldElement))) } +// fn is_unit(self) -> bool +fn type_is_unit(arguments: Vec<(Value, Location)>, location: Location) -> IResult { + let value = check_one_argument(arguments, location)?; + let typ = get_type(value)?; + + Ok(Value::Bool(matches!(typ, Type::Unit))) +} + // fn type_of(x: T) -> Type fn type_of(arguments: Vec<(Value, Location)>, location: Location) -> IResult { let (value, _) = check_one_argument(arguments, location)?; diff --git a/docs/docs/noir/standard_library/meta/typ.md b/docs/docs/noir/standard_library/meta/typ.md index 1334092a9fa..0be48ddc848 100644 --- a/docs/docs/noir/standard_library/meta/typ.md +++ b/docs/docs/noir/standard_library/meta/typ.md @@ -146,6 +146,12 @@ fn foo() where T: Default { `true` if this type is `Field`. +### is_unit + +#include_code is_unit noir_stdlib/src/meta/typ.nr rust + +`true` if this type is the unit `()` type. + ## Trait Implementations ```rust diff --git a/noir_stdlib/src/meta/typ.nr b/noir_stdlib/src/meta/typ.nr index d692f6e5a7e..ef0dfc450c7 100644 --- a/noir_stdlib/src/meta/typ.nr +++ b/noir_stdlib/src/meta/typ.nr @@ -8,59 +8,64 @@ pub comptime fn fresh_type_variable() -> Type {} impl Type { #[builtin(type_as_array)] -// docs:start:as_array + // docs:start:as_array comptime fn as_array(self) -> Option<(Type, Type)> {} // docs:end:as_array #[builtin(type_as_constant)] -// docs:start:as_constant + // docs:start:as_constant comptime fn as_constant(self) -> Option {} // docs:end:as_constant #[builtin(type_as_integer)] -// docs:start:as_integer + // docs:start:as_integer comptime fn as_integer(self) -> Option<(bool, u8)> {} // docs:end:as_integer #[builtin(type_as_slice)] -// docs:start:as_slice + // docs:start:as_slice comptime fn as_slice(self) -> Option {} // docs:end:as_slice #[builtin(type_as_str)] -// docs:start:as_str + // docs:start:as_str comptime fn as_str(self) -> Option {} // docs:end:as_str #[builtin(type_as_struct)] -// docs:start:as_struct + // docs:start:as_struct comptime fn as_struct(self) -> Option<(StructDefinition, [Type])> {} // docs:end:as_struct #[builtin(type_as_tuple)] -// docs:start:as_tuple + // docs:start:as_tuple comptime fn as_tuple(self) -> Option<[Type]> {} // docs:end:as_tuple #[builtin(type_get_trait_impl)] -// docs:start:get_trait_impl + // docs:start:get_trait_impl comptime fn get_trait_impl(self, constraint: TraitConstraint) -> Option {} // docs:end:get_trait_impl #[builtin(type_implements)] -// docs:start:implements + // docs:start:implements comptime fn implements(self, constraint: TraitConstraint) -> bool {} // docs:end:implements #[builtin(type_is_bool)] -// docs:start:is_bool + // docs:start:is_bool comptime fn is_bool(self) -> bool {} // docs:end:is_bool #[builtin(type_is_field)] -// docs:start:is_field + // docs:start:is_field comptime fn is_field(self) -> bool {} // docs:end:is_field + + #[builtin(type_is_unit)] + // docs:start:is_unit + comptime fn is_unit(self) -> bool {} + // docs:end:is_unit } impl Eq for Type { diff --git a/test_programs/compile_success_empty/comptime_type/src/main.nr b/test_programs/compile_success_empty/comptime_type/src/main.nr index c9307570c87..8e5c3005d9d 100644 --- a/test_programs/compile_success_empty/comptime_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_type/src/main.nr @@ -150,6 +150,10 @@ fn main() { // Now typevar2 should be bound to the serialized pair size 2 times the array length 5 assert_eq(typevar2.as_constant().unwrap(), 10); // docs:end:fresh-type-variable-example + + // Check Type::is_unit + let unit = quote { () }.as_type(); + assert(unit.is_unit()); } } From 8dcc44a022c10b9544babbc80d6ed0234bcdda26 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:35:24 -0300 Subject: [PATCH 02/11] Add `UnresolvedType::is_bool` --- .../src/hir/comptime/interpreter/builtin.rs | 12 ++++++++++++ .../noir/standard_library/meta/unresolved_type.md | 6 ++++++ noir_stdlib/src/meta/unresolved_type.nr | 5 +++++ .../comptime_unresolved_type/Nargo.toml | 7 +++++++ .../comptime_unresolved_type/src/main.nr | 12 ++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 test_programs/compile_success_empty/comptime_unresolved_type/Nargo.toml create mode 100644 test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 20c8265c200..2e49d43fa1c 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -193,6 +193,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "typed_expr_get_type" => { typed_expr_get_type(interner, arguments, return_type, location) } + "unresolved_type_is_bool" => unresolved_type_is_bool(interner, arguments, location), "unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location), "zeroed" => zeroed(return_type), _ => { @@ -1122,6 +1123,17 @@ fn typed_expr_get_type( option(return_type, option_value) } +// fn is_bool(self) -> bool +fn unresolved_type_is_bool( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let typ = get_unresolved_type(interner, self_argument)?; + Ok(Value::Bool(matches!(typ, UnresolvedTypeData::Bool))) +} + // fn is_field(self) -> bool fn unresolved_type_is_field( interner: &NodeInterner, diff --git a/docs/docs/noir/standard_library/meta/unresolved_type.md b/docs/docs/noir/standard_library/meta/unresolved_type.md index 9c61f91dee2..5eaeb30c1fb 100644 --- a/docs/docs/noir/standard_library/meta/unresolved_type.md +++ b/docs/docs/noir/standard_library/meta/unresolved_type.md @@ -6,6 +6,12 @@ title: UnresolvedType ## Methods +### is_bool + +#include_code is_bool noir_stdlib/src/meta/unresolved_type.nr rust + +Returns `true` if this type is `bool`. + ### is_field #include_code is_field noir_stdlib/src/meta/unresolved_type.nr rust diff --git a/noir_stdlib/src/meta/unresolved_type.nr b/noir_stdlib/src/meta/unresolved_type.nr index f53635414cc..481800a61c7 100644 --- a/noir_stdlib/src/meta/unresolved_type.nr +++ b/noir_stdlib/src/meta/unresolved_type.nr @@ -1,4 +1,9 @@ impl UnresolvedType { + #[builtin(unresolved_type_is_bool)] + // docs:start:is_bool + comptime fn is_bool(self) -> bool {} + // docs:end:is_bool + #[builtin(unresolved_type_is_field)] // docs:start:is_field comptime fn is_field(self) -> bool {} diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/Nargo.toml b/test_programs/compile_success_empty/comptime_unresolved_type/Nargo.toml new file mode 100644 index 00000000000..cc266b9b9c5 --- /dev/null +++ b/test_programs/compile_success_empty/comptime_unresolved_type/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "comptime_unresolved_type" +type = "bin" +authors = [""] +compiler_version = ">=0.31.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr new file mode 100644 index 00000000000..0fde81a2976 --- /dev/null +++ b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr @@ -0,0 +1,12 @@ +fn main() { + comptime + { + // Check UnresolvedType::is_bool + let typ = quote { x as bool }.as_expr().unwrap().as_cast().unwrap().1; + assert(typ.is_bool()); + + // Check UnresolvedType::is_field + let typ = quote { x as Field }.as_expr().unwrap().as_cast().unwrap().1; + assert(typ.is_field()); + } +} From 2c2256de4f8f3c360c253682922f2e949969927b Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:38:00 -0300 Subject: [PATCH 03/11] Add `UnresolvedType::is_unit` --- .../src/hir/comptime/interpreter/builtin.rs | 12 ++++++++++++ .../noir/standard_library/meta/unresolved_type.md | 6 ++++++ noir_stdlib/src/meta/unresolved_type.nr | 5 +++++ .../comptime_unresolved_type/src/main.nr | 4 ++++ 4 files changed, 27 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 2e49d43fa1c..bcc07dbb905 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -195,6 +195,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { } "unresolved_type_is_bool" => unresolved_type_is_bool(interner, arguments, location), "unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location), + "unresolved_type_is_unit" => unresolved_type_is_unit(interner, arguments, location), "zeroed" => zeroed(return_type), _ => { let item = format!("Comptime evaluation for builtin function {name}"); @@ -1145,6 +1146,17 @@ fn unresolved_type_is_field( Ok(Value::Bool(matches!(typ, UnresolvedTypeData::FieldElement))) } +// fn is_unit(self) -> bool +fn unresolved_type_is_unit( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + let typ = get_unresolved_type(interner, self_argument)?; + Ok(Value::Bool(matches!(typ, UnresolvedTypeData::Unit))) +} + // fn zeroed() -> T fn zeroed(return_type: Type) -> IResult { match return_type { diff --git a/docs/docs/noir/standard_library/meta/unresolved_type.md b/docs/docs/noir/standard_library/meta/unresolved_type.md index 5eaeb30c1fb..4d81c73d76e 100644 --- a/docs/docs/noir/standard_library/meta/unresolved_type.md +++ b/docs/docs/noir/standard_library/meta/unresolved_type.md @@ -17,3 +17,9 @@ Returns `true` if this type is `bool`. #include_code is_field noir_stdlib/src/meta/unresolved_type.nr rust Returns true if this type refers to the Field type. + +### is_unit + +#include_code is_unit noir_stdlib/src/meta/unresolved_type.nr rust + +Returns true if this type is the unit `()` type. diff --git a/noir_stdlib/src/meta/unresolved_type.nr b/noir_stdlib/src/meta/unresolved_type.nr index 481800a61c7..d792186cb00 100644 --- a/noir_stdlib/src/meta/unresolved_type.nr +++ b/noir_stdlib/src/meta/unresolved_type.nr @@ -8,4 +8,9 @@ impl UnresolvedType { // docs:start:is_field comptime fn is_field(self) -> bool {} // docs:end:is_field + + #[builtin(unresolved_type_is_unit)] + // docs:start:is_unit + comptime fn is_unit(self) -> bool {} + // docs:end:is_unit } diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr index 0fde81a2976..cb247624cc3 100644 --- a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr @@ -8,5 +8,9 @@ fn main() { // Check UnresolvedType::is_field let typ = quote { x as Field }.as_expr().unwrap().as_cast().unwrap().1; assert(typ.is_field()); + + // Check UnresolvedType::is_unit + let typ = quote { x as () }.as_expr().unwrap().as_cast().unwrap().1; + assert(typ.is_unit()); } } From c6aa06a74180f0595ab2e3222f81185c5a060acc Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:44:04 -0300 Subject: [PATCH 04/11] Add `Type::as_mutable_reference` --- .../src/hir/comptime/interpreter/builtin.rs | 18 ++++++++++++++++++ docs/docs/noir/standard_library/meta/typ.md | 6 ++++++ noir_stdlib/src/meta/typ.nr | 5 +++++ .../comptime_type/src/main.nr | 4 ++++ 4 files changed, 33 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index bcc07dbb905..cdd84173518 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -174,6 +174,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "type_as_array" => type_as_array(arguments, return_type, location), "type_as_constant" => type_as_constant(arguments, return_type, location), "type_as_integer" => type_as_integer(arguments, return_type, location), + "type_as_mutable_reference" => { + type_as_mutable_reference(arguments, return_type, location) + } "type_as_slice" => type_as_slice(arguments, return_type, location), "type_as_str" => type_as_str(arguments, return_type, location), "type_as_struct" => type_as_struct(arguments, return_type, location), @@ -814,6 +817,21 @@ fn type_as_integer( }) } +// fn as_mutable_reference(self) -> Option +fn type_as_mutable_reference( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + type_as(arguments, return_type, location, |typ| { + if let Type::MutableReference(typ) = typ { + Some(Value::Type(*typ)) + } else { + None + } + }) +} + // fn as_slice(self) -> Option fn type_as_slice( arguments: Vec<(Value, Location)>, diff --git a/docs/docs/noir/standard_library/meta/typ.md b/docs/docs/noir/standard_library/meta/typ.md index 0be48ddc848..40d97146c3d 100644 --- a/docs/docs/noir/standard_library/meta/typ.md +++ b/docs/docs/noir/standard_library/meta/typ.md @@ -63,6 +63,12 @@ return the numeric constant. If this is an integer type, return a boolean which is `true` if the type is signed, as well as the number of bits of this integer type. +### as_mutable_reference + +#include_code as_mutable_reference noir_stdlib/src/meta/typ.nr rust + +If this is a mutable reference type `&mut T`, retursn the mutable type `T`. + ### as_slice #include_code as_slice noir_stdlib/src/meta/typ.nr rust diff --git a/noir_stdlib/src/meta/typ.nr b/noir_stdlib/src/meta/typ.nr index ef0dfc450c7..44162e920bd 100644 --- a/noir_stdlib/src/meta/typ.nr +++ b/noir_stdlib/src/meta/typ.nr @@ -22,6 +22,11 @@ impl Type { comptime fn as_integer(self) -> Option<(bool, u8)> {} // docs:end:as_integer + #[builtin(type_as_mutable_reference)] + // docs:start:as_mutable_reference + comptime fn as_mutable_reference(self) -> Option {} + // docs:end:as_mutable_reference + #[builtin(type_as_slice)] // docs:start:as_slice comptime fn as_slice(self) -> Option {} diff --git a/test_programs/compile_success_empty/comptime_type/src/main.nr b/test_programs/compile_success_empty/comptime_type/src/main.nr index 8e5c3005d9d..64e3cec2fce 100644 --- a/test_programs/compile_success_empty/comptime_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_type/src/main.nr @@ -154,6 +154,10 @@ fn main() { // Check Type::is_unit let unit = quote { () }.as_type(); assert(unit.is_unit()); + + // Check Type::as_mutable_reference + let typ = quote { &mut Field }.as_type(); + assert_eq(typ.as_mutable_reference().unwrap(), quote { Field }.as_type()); } } From 81644e8ab51a7b9931864c2a3f5f04f6c71c3c0f Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:50:13 -0300 Subject: [PATCH 05/11] Add `UnresolvedType::as_mutable_reference` --- .../src/hir/comptime/interpreter/builtin.rs | 38 +++++++++++++++++++ .../standard_library/meta/unresolved_type.md | 6 +++ noir_stdlib/src/meta/unresolved_type.nr | 7 ++++ .../comptime_unresolved_type/src/main.nr | 4 ++ 4 files changed, 55 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index cdd84173518..802f7fb168d 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -196,6 +196,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "typed_expr_get_type" => { typed_expr_get_type(interner, arguments, return_type, location) } + "unresolved_type_as_mutable_reference" => { + unresolved_type_as_mutable_reference(interner, arguments, return_type, location) + } "unresolved_type_is_bool" => unresolved_type_is_bool(interner, arguments, location), "unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location), "unresolved_type_is_unit" => unresolved_type_is_unit(interner, arguments, location), @@ -1142,6 +1145,22 @@ fn typed_expr_get_type( option(return_type, option_value) } +// fn as_mutable_reference(self) -> Option +fn unresolved_type_as_mutable_reference( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + unresolved_type_as(interner, arguments, return_type, location, |typ| { + if let UnresolvedTypeData::MutableReference(typ) = typ { + Some(Value::UnresolvedType(typ.typ)) + } else { + None + } + }) +} + // fn is_bool(self) -> bool fn unresolved_type_is_bool( interner: &NodeInterner, @@ -1175,6 +1194,25 @@ fn unresolved_type_is_unit( Ok(Value::Bool(matches!(typ, UnresolvedTypeData::Unit))) } +// Helper function for implementing the `unresolved_type_as_...` functions. +fn unresolved_type_as( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, + f: F, +) -> IResult +where + F: FnOnce(UnresolvedTypeData) -> Option, +{ + let value = check_one_argument(arguments, location)?; + let typ = get_unresolved_type(interner, value)?; + + let option_value = f(typ); + + option(return_type, option_value) +} + // fn zeroed() -> T fn zeroed(return_type: Type) -> IResult { match return_type { diff --git a/docs/docs/noir/standard_library/meta/unresolved_type.md b/docs/docs/noir/standard_library/meta/unresolved_type.md index 4d81c73d76e..543b0dcab70 100644 --- a/docs/docs/noir/standard_library/meta/unresolved_type.md +++ b/docs/docs/noir/standard_library/meta/unresolved_type.md @@ -6,6 +6,12 @@ title: UnresolvedType ## Methods +### as_mutable_reference + +#include_code as_mutable_reference noir_stdlib/src/meta/unresolved_type.nr rust + +If this is a mutable reference type `&mut T`, retursn the mutable type `T`. + ### is_bool #include_code is_bool noir_stdlib/src/meta/unresolved_type.nr rust diff --git a/noir_stdlib/src/meta/unresolved_type.nr b/noir_stdlib/src/meta/unresolved_type.nr index d792186cb00..4b5661420a8 100644 --- a/noir_stdlib/src/meta/unresolved_type.nr +++ b/noir_stdlib/src/meta/unresolved_type.nr @@ -1,4 +1,11 @@ +use crate::option::Option; + impl UnresolvedType { + #[builtin(unresolved_type_as_mutable_reference)] + // docs:start:as_mutable_reference + comptime fn as_mutable_reference(self) -> Option {} + // docs:end:as_mutable_reference + #[builtin(unresolved_type_is_bool)] // docs:start:is_bool comptime fn is_bool(self) -> bool {} diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr index cb247624cc3..163a22733dd 100644 --- a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr @@ -12,5 +12,9 @@ fn main() { // Check UnresolvedType::is_unit let typ = quote { x as () }.as_expr().unwrap().as_cast().unwrap().1; assert(typ.is_unit()); + + // Check UnresolvedType::as_mutable_reference + let typ = quote { x as &mut Field }.as_expr().unwrap().as_cast().unwrap().1; + assert(typ.as_mutable_reference().unwrap().is_field()); } } From 7c5909d1b57cd2cdcd99b20ac9125bc79f906b75 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:52:27 -0300 Subject: [PATCH 06/11] Add `UnresolvedType::as_slice` --- .../src/hir/comptime/interpreter/builtin.rs | 19 +++++++++++++++++++ .../standard_library/meta/unresolved_type.md | 6 ++++++ noir_stdlib/src/meta/unresolved_type.nr | 5 +++++ .../comptime_unresolved_type/src/main.nr | 4 ++++ 4 files changed, 34 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 802f7fb168d..bc0f2be9e9a 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -199,6 +199,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "unresolved_type_as_mutable_reference" => { unresolved_type_as_mutable_reference(interner, arguments, return_type, location) } + "unresolved_type_as_slice" => { + unresolved_type_as_slice(interner, arguments, return_type, location) + } "unresolved_type_is_bool" => unresolved_type_is_bool(interner, arguments, location), "unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location), "unresolved_type_is_unit" => unresolved_type_is_unit(interner, arguments, location), @@ -1161,6 +1164,22 @@ fn unresolved_type_as_mutable_reference( }) } +// fn as_slice(self) -> Option +fn unresolved_type_as_slice( + interner: &NodeInterner, + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + unresolved_type_as(interner, arguments, return_type, location, |typ| { + if let UnresolvedTypeData::Slice(typ) = typ { + Some(Value::UnresolvedType(typ.typ)) + } else { + None + } + }) +} + // fn is_bool(self) -> bool fn unresolved_type_is_bool( interner: &NodeInterner, diff --git a/docs/docs/noir/standard_library/meta/unresolved_type.md b/docs/docs/noir/standard_library/meta/unresolved_type.md index 543b0dcab70..dc7933db704 100644 --- a/docs/docs/noir/standard_library/meta/unresolved_type.md +++ b/docs/docs/noir/standard_library/meta/unresolved_type.md @@ -12,6 +12,12 @@ title: UnresolvedType If this is a mutable reference type `&mut T`, retursn the mutable type `T`. +### as_slice + +#include_code as_slice noir_stdlib/src/meta/unresolved_type.nr rust + +If this is a slice `&[T]`, retursn the element type `T`. + ### is_bool #include_code is_bool noir_stdlib/src/meta/unresolved_type.nr rust diff --git a/noir_stdlib/src/meta/unresolved_type.nr b/noir_stdlib/src/meta/unresolved_type.nr index 4b5661420a8..f5e2298be41 100644 --- a/noir_stdlib/src/meta/unresolved_type.nr +++ b/noir_stdlib/src/meta/unresolved_type.nr @@ -6,6 +6,11 @@ impl UnresolvedType { comptime fn as_mutable_reference(self) -> Option {} // docs:end:as_mutable_reference + #[builtin(unresolved_type_as_slice)] + // docs:start:as_slice + comptime fn as_slice(self) -> Option {} + // docs:end:as_slice + #[builtin(unresolved_type_is_bool)] // docs:start:is_bool comptime fn is_bool(self) -> bool {} diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr index 163a22733dd..f161064800e 100644 --- a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr @@ -16,5 +16,9 @@ fn main() { // Check UnresolvedType::as_mutable_reference let typ = quote { x as &mut Field }.as_expr().unwrap().as_cast().unwrap().1; assert(typ.as_mutable_reference().unwrap().is_field()); + + // Check UnresolvedType::as_slice + let typ = quote { x as &[Field] }.as_expr().unwrap().as_cast().unwrap().1; + assert(typ.as_slice().unwrap().is_field()); } } From a9a988a205393ffdbfe984358720b748db79469a Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 15:56:49 -0300 Subject: [PATCH 07/11] Fix typo --- docs/docs/noir/standard_library/meta/typ.md | 2 +- docs/docs/noir/standard_library/meta/unresolved_type.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/noir/standard_library/meta/typ.md b/docs/docs/noir/standard_library/meta/typ.md index 40d97146c3d..cb765a5a681 100644 --- a/docs/docs/noir/standard_library/meta/typ.md +++ b/docs/docs/noir/standard_library/meta/typ.md @@ -67,7 +67,7 @@ if the type is signed, as well as the number of bits of this integer type. #include_code as_mutable_reference noir_stdlib/src/meta/typ.nr rust -If this is a mutable reference type `&mut T`, retursn the mutable type `T`. +If this is a mutable reference type `&mut T`, returns the mutable type `T`. ### as_slice diff --git a/docs/docs/noir/standard_library/meta/unresolved_type.md b/docs/docs/noir/standard_library/meta/unresolved_type.md index dc7933db704..8535cbab19c 100644 --- a/docs/docs/noir/standard_library/meta/unresolved_type.md +++ b/docs/docs/noir/standard_library/meta/unresolved_type.md @@ -10,13 +10,13 @@ title: UnresolvedType #include_code as_mutable_reference noir_stdlib/src/meta/unresolved_type.nr rust -If this is a mutable reference type `&mut T`, retursn the mutable type `T`. +If this is a mutable reference type `&mut T`, returns the mutable type `T`. ### as_slice #include_code as_slice noir_stdlib/src/meta/unresolved_type.nr rust -If this is a slice `&[T]`, retursn the element type `T`. +If this is a slice `&[T]`, returns the element type `T`. ### is_bool From 693be83dcbf6d05de36a4c36722a2c4b27355886 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 16:03:57 -0300 Subject: [PATCH 08/11] Add Noir doc comments to Type and UnresolvedType impls --- noir_stdlib/src/meta/typ.nr | 116 ++++++++++++++++++++++++ noir_stdlib/src/meta/unresolved_type.nr | 7 ++ 2 files changed, 123 insertions(+) diff --git a/noir_stdlib/src/meta/typ.nr b/noir_stdlib/src/meta/typ.nr index 44162e920bd..518ba60f270 100644 --- a/noir_stdlib/src/meta/typ.nr +++ b/noir_stdlib/src/meta/typ.nr @@ -1,72 +1,185 @@ +//! Contains methods on the built-in `Type` type used for representing a type in the source program. + use crate::cmp::Eq; use crate::option::Option; +/// Creates and returns an unbound type variable. This is a special kind of type internal +/// to type checking which will type check with any other type. When it is type checked +/// against another type it will also be set to that type. For example, if `a` is a type +/// variable and we have the type equality `(a, i32) = (u8, i32)`, the compiler will set +/// `a` equal to `u8`. +/// +/// Unbound type variables will often be rendered as `_` while printing them. Bound type +/// variables will appear as the type they are bound to. +/// +/// This can be used in conjunction with functions which internally perform type checks +/// such as `Type::implements` or `Type::get_trait_impl` to potentially grab some of the types used. +/// +/// Note that calling `Type::implements` or `Type::get_trait_impl` on a type variable will always +/// fail. +/// +/// Example: +/// +/// ```noir +/// trait Serialize {} +/// +/// impl Serialize<1> for Field {} +/// +/// impl Serialize for [T; N] +/// where T: Serialize {} +/// +/// impl Serialize for (T, U) +/// where T: Serialize, U: Serialize {} +/// +/// fn fresh_variable_example() { +/// let typevar1 = std::meta::typ::fresh_type_variable(); +/// let constraint = quote { Serialize<$typevar1> }.as_trait_constraint(); +/// let field_type = quote { Field }.as_type(); +/// +/// // Search for a trait impl (binding typevar1 to 1 when the impl is found): +/// assert(field_type.implements(constraint)); +/// +/// // typevar1 should be bound to the "1" generic now: +/// assert_eq(typevar1.as_constant().unwrap(), 1); +/// +/// // If we want to do the same with a different type, we need to +/// // create a new type variable now that `typevar1` is bound +/// let typevar2 = std::meta::typ::fresh_type_variable(); +/// let constraint = quote { Serialize<$typevar2> }.as_trait_constraint(); +/// let array_type = quote { [(Field, Field); 5] }.as_type(); +/// assert(array_type.implements(constraint)); +/// +/// // Now typevar2 should be bound to the serialized pair size 2 times the array length 5 +/// assert_eq(typevar2.as_constant().unwrap(), 10); +/// } +/// ``` #[builtin(fresh_type_variable)] // docs:start:fresh_type_variable pub comptime fn fresh_type_variable() -> Type {} // docs:end:fresh_type_variable impl Type { + /// If this type is an array, return a pair of (element type, size type). + /// + /// Example: + /// + /// ```rust + /// comptime { + /// let array_type = quote { [Field; 3] }.as_type(); + /// let (field_type, three_type) = array_type.as_array().unwrap(); + /// + /// assert(field_type.is_field()); + /// assert_eq(three_type.as_constant().unwrap(), 3); + /// } + /// ``` #[builtin(type_as_array)] // docs:start:as_array comptime fn as_array(self) -> Option<(Type, Type)> {} // docs:end:as_array + /// If this type is a constant integer (such as the `3` in the array type `[Field; 3]`), + /// return the numeric constant. #[builtin(type_as_constant)] // docs:start:as_constant comptime fn as_constant(self) -> Option {} // docs:end:as_constant + /// If this is an integer type, return a boolean which is `true` + /// if the type is signed, as well as the number of bits of this integer type. #[builtin(type_as_integer)] // docs:start:as_integer comptime fn as_integer(self) -> Option<(bool, u8)> {} // docs:end:as_integer + /// If this is a mutable reference type `&mut T`, returns the mutable type `T`. #[builtin(type_as_mutable_reference)] // docs:start:as_mutable_reference comptime fn as_mutable_reference(self) -> Option {} // docs:end:as_mutable_reference + /// If this is a slice type, return the element type of the slice. #[builtin(type_as_slice)] // docs:start:as_slice comptime fn as_slice(self) -> Option {} // docs:end:as_slice + /// If this is a `str` type, returns the length `N` as a type. #[builtin(type_as_str)] // docs:start:as_str comptime fn as_str(self) -> Option {} // docs:end:as_str + /// If this is a struct type, returns the struct in addition to any generic arguments on this type. #[builtin(type_as_struct)] // docs:start:as_struct comptime fn as_struct(self) -> Option<(StructDefinition, [Type])> {} // docs:end:as_struct + /// If this is a tuple type, returns each element type of the tuple. #[builtin(type_as_tuple)] // docs:start:as_tuple comptime fn as_tuple(self) -> Option<[Type]> {} // docs:end:as_tuple + /// Retrieves the trait implementation that implements the given + /// trait constraint for this type. If the trait constraint is not + /// found, `None` is returned. Note that since the concrete trait implementation + /// for a trait constraint specified from a `where` clause is unknown, + /// this function will return `None` in these cases. If you only want to know + /// whether a type implements a trait, use `implements` instead. + /// + /// Example: + /// + /// ```rust + /// comptime { + /// let field_type = quote { Field }.as_type(); + /// let default = quote { Default }.as_trait_constraint(); + /// + /// let the_impl: TraitImpl = field_type.get_trait_impl(default).unwrap(); + /// assert(the_impl.methods().len(), 1); + /// } + /// ``` #[builtin(type_get_trait_impl)] // docs:start:get_trait_impl comptime fn get_trait_impl(self, constraint: TraitConstraint) -> Option {} // docs:end:get_trait_impl + /// Returns `true` if this type implements the given trait. Note that unlike + /// `get_trait_impl` this will also return true for any `where` constraints + /// in scope. + /// + /// Example: + /// + /// ```rust + /// fn foo() where T: Default { + /// comptime { + /// let field_type = quote { Field }.as_type(); + /// let default = quote { Default }.as_trait_constraint(); + /// assert(field_type.implements(default)); + /// + /// let t = quote { T }.as_type(); + /// assert(t.implements(default)); + /// } + /// } + /// ``` #[builtin(type_implements)] // docs:start:implements comptime fn implements(self, constraint: TraitConstraint) -> bool {} // docs:end:implements + /// Returns `true` if this type is `bool`. #[builtin(type_is_bool)] // docs:start:is_bool comptime fn is_bool(self) -> bool {} // docs:end:is_bool + /// Returns `true` if this type is `Field`. #[builtin(type_is_field)] // docs:start:is_field comptime fn is_field(self) -> bool {} // docs:end:is_field + /// Returns `true` if this type is the unit `()` type. #[builtin(type_is_unit)] // docs:start:is_unit comptime fn is_unit(self) -> bool {} @@ -74,6 +187,9 @@ impl Type { } impl Eq for Type { + /// Note that this is syntactic equality, this is not the same as whether two types will type check + /// to be the same type. Unless type inference or generics are being used however, users should not + /// typically have to worry about this distinction. comptime fn eq(self, other: Self) -> bool { type_eq(self, other) } diff --git a/noir_stdlib/src/meta/unresolved_type.nr b/noir_stdlib/src/meta/unresolved_type.nr index f5e2298be41..7be940ff8e9 100644 --- a/noir_stdlib/src/meta/unresolved_type.nr +++ b/noir_stdlib/src/meta/unresolved_type.nr @@ -1,26 +1,33 @@ +//! Contains methods on the built-in `UnresolvedType` type for the syntax of types. + use crate::option::Option; impl UnresolvedType { + /// If this is a mutable reference type `&mut T`, returns the mutable type `T`. #[builtin(unresolved_type_as_mutable_reference)] // docs:start:as_mutable_reference comptime fn as_mutable_reference(self) -> Option {} // docs:end:as_mutable_reference + /// If this is a slice `&[T]`, returns the element type `T`. #[builtin(unresolved_type_as_slice)] // docs:start:as_slice comptime fn as_slice(self) -> Option {} // docs:end:as_slice + /// Returns `true` if this type is `bool`. #[builtin(unresolved_type_is_bool)] // docs:start:is_bool comptime fn is_bool(self) -> bool {} // docs:end:is_bool + /// Returns true if this type refers to the `Field` type. #[builtin(unresolved_type_is_field)] // docs:start:is_field comptime fn is_field(self) -> bool {} // docs:end:is_field + /// Returns true if this type is the unit `()` type. #[builtin(unresolved_type_is_unit)] // docs:start:is_unit comptime fn is_unit(self) -> bool {} From 22a71e569902c3561756620ee0edffca0cfb5b96 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 16:16:53 -0300 Subject: [PATCH 09/11] Fix test program --- .../compile_success_empty/comptime_unresolved_type/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr index f161064800e..a2425a9b6a9 100644 --- a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr @@ -18,7 +18,7 @@ fn main() { assert(typ.as_mutable_reference().unwrap().is_field()); // Check UnresolvedType::as_slice - let typ = quote { x as &[Field] }.as_expr().unwrap().as_cast().unwrap().1; + let typ = quote { let x: &[Field] = 1; }.as_expr().unwrap().as_let().unwrap().1.unwrap(); assert(typ.as_slice().unwrap().is_field()); } } From ff07904d857771b20888f198da57914b281bf993 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 10 Sep 2024 16:38:45 -0300 Subject: [PATCH 10/11] Get it right this time --- .../compile_success_empty/comptime_unresolved_type/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr index a2425a9b6a9..aba4461d4af 100644 --- a/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr +++ b/test_programs/compile_success_empty/comptime_unresolved_type/src/main.nr @@ -18,7 +18,7 @@ fn main() { assert(typ.as_mutable_reference().unwrap().is_field()); // Check UnresolvedType::as_slice - let typ = quote { let x: &[Field] = 1; }.as_expr().unwrap().as_let().unwrap().1.unwrap(); + let typ = quote { x as [Field] }.as_expr().unwrap().as_cast().unwrap().1; assert(typ.as_slice().unwrap().is_field()); } } From 534d144b82ec416d11324d12cf6e716c2098bcf7 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 7 Oct 2024 08:15:37 -0300 Subject: [PATCH 11/11] Update noir_stdlib/src/meta/typ.nr Co-authored-by: Maxim Vezenov --- noir_stdlib/src/meta/typ.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir_stdlib/src/meta/typ.nr b/noir_stdlib/src/meta/typ.nr index 518ba60f270..dd4a667ec50 100644 --- a/noir_stdlib/src/meta/typ.nr +++ b/noir_stdlib/src/meta/typ.nr @@ -63,7 +63,7 @@ impl Type { /// /// Example: /// - /// ```rust + /// ```noir /// comptime { /// let array_type = quote { [Field; 3] }.as_type(); /// let (field_type, three_type) = array_type.as_array().unwrap();