From 278462cab8f0b072baa14a2e5f7b5752af4382df Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 21 Jun 2024 14:52:57 -0500 Subject: [PATCH 1/4] Implement evaluation of member access on tuples --- compiler/noirc_frontend/src/hir/comptime/interpreter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 0a5aaef7cbf..0803d06a508 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -927,6 +927,14 @@ impl<'a> Interpreter<'a> { fn evaluate_access(&mut self, access: HirMemberAccess, id: ExprId) -> IResult { let (fields, struct_type) = match self.evaluate(access.lhs)? { Value::Struct(fields, typ) => (fields, typ), + Value::Tuple(fields) => { + let mut field_types = Vec::with_capacity(fields.len()); + let fields = fields.into_iter().enumerate().map(|(i, field)| { + field_types.push(field.get_type().into_owned()); + (Rc::new(i.to_string()), field) + }).collect(); + (fields, Type::Tuple(field_types)) + } value => { let location = self.interner.expr_location(&id); return Err(InterpreterError::NonTupleOrStructInMemberAccess { value, location }); From 521ac4acf2e307c9f6698fb39b5dd13aced7985d Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 21 Jun 2024 15:01:21 -0500 Subject: [PATCH 2/4] Format --- .../noirc_frontend/src/hir/comptime/interpreter.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 0803d06a508..565aa1f6d51 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -929,10 +929,14 @@ impl<'a> Interpreter<'a> { Value::Struct(fields, typ) => (fields, typ), Value::Tuple(fields) => { let mut field_types = Vec::with_capacity(fields.len()); - let fields = fields.into_iter().enumerate().map(|(i, field)| { - field_types.push(field.get_type().into_owned()); - (Rc::new(i.to_string()), field) - }).collect(); + let fields = fields + .into_iter() + .enumerate() + .map(|(i, field)| { + field_types.push(field.get_type().into_owned()); + (Rc::new(i.to_string()), field) + }) + .collect(); (fields, Type::Tuple(field_types)) } value => { From e9a7b4ed0977423c9f58738af827b5484553ba1f Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 24 Jun 2024 12:22:48 -0500 Subject: [PATCH 3/4] Update compiler/noirc_frontend/src/hir/comptime/interpreter.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- .../noirc_frontend/src/hir/comptime/interpreter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 565aa1f6d51..5e236a2b980 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -928,15 +928,15 @@ impl<'a> Interpreter<'a> { let (fields, struct_type) = match self.evaluate(access.lhs)? { Value::Struct(fields, typ) => (fields, typ), Value::Tuple(fields) => { - let mut field_types = Vec::with_capacity(fields.len()); - let fields = fields + let (fields, field_types): (HashMap, Value>, Vec) = fields .into_iter() .enumerate() .map(|(i, field)| { - field_types.push(field.get_type().into_owned()); - (Rc::new(i.to_string()), field) + let field_type = field.get_type().into_owned(); + let key_val_pair = (Rc::new(i.to_string()), field); + (key_val_pair, field_type) }) - .collect(); + .unzip(); (fields, Type::Tuple(field_types)) } value => { From 2825fef126da132402066e0bc3f944917b5b8f61 Mon Sep 17 00:00:00 2001 From: jfecher Date: Mon, 24 Jun 2024 13:21:28 -0500 Subject: [PATCH 4/4] feat: Implement `slice_push_back` in the comptime interpreter (#5312) # Description ## Problem\* ## Summary\* Implements `slice_push_back` in the comptime interpreter. This was needed in the vertical slice example to build a slice of quoted fields for the type in the impl. ## Additional Context With this a slightly modified version of the vertical slice code now runs. Notably: - Generic functions do not work, so a `map` function like in the original cannot be used - An annotation function can return a quoted impl, but the impl isn't actually inserted into the program yet. So the derived impl does nothing currently. ## Documentation\* Check one: - [x] No documentation needed. - [ ] 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. --- .../src/hir/comptime/interpreter/builtin.rs | 15 +++++++ .../derive_impl/Nargo.toml | 7 +++ .../derive_impl/src/main.nr | 44 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 test_programs/compile_success_empty/derive_impl/Nargo.toml create mode 100644 test_programs/compile_success_empty/derive_impl/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 b82e915f777..cccc9c6d545 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -19,6 +19,7 @@ pub(super) fn call_builtin( match name { "array_len" => array_len(&arguments), "as_slice" => as_slice(arguments), + "slice_push_back" => slice_push_back(arguments), "type_def_as_type" => type_def_as_type(interner, arguments), "type_def_generics" => type_def_generics(interner, arguments), "type_def_fields" => type_def_fields(interner, arguments), @@ -48,6 +49,20 @@ fn as_slice(mut arguments: Vec<(Value, Location)>) -> IResult { } } +fn slice_push_back(mut arguments: Vec<(Value, Location)>) -> IResult { + assert_eq!(arguments.len(), 2, "ICE: `slice_push_back` should only receive two arguments"); + let (element, _) = arguments.pop().unwrap(); + let (slice, _) = arguments.pop().unwrap(); + match slice { + Value::Slice(mut values, typ) => { + values.push_back(element); + Ok(Value::Slice(values, typ)) + } + // Type checking should prevent this branch being taken. + _ => unreachable!("ICE: `slice_push_back` expects a slice as its first argument"), + } +} + /// fn as_type(self) -> Quoted fn type_def_as_type( interner: &NodeInterner, diff --git a/test_programs/compile_success_empty/derive_impl/Nargo.toml b/test_programs/compile_success_empty/derive_impl/Nargo.toml new file mode 100644 index 00000000000..26a6020a6b1 --- /dev/null +++ b/test_programs/compile_success_empty/derive_impl/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "derive_impl" +type = "bin" +authors = [""] +compiler_version = ">=0.30.0" + +[dependencies] diff --git a/test_programs/compile_success_empty/derive_impl/src/main.nr b/test_programs/compile_success_empty/derive_impl/src/main.nr new file mode 100644 index 00000000000..abad6d4f8e1 --- /dev/null +++ b/test_programs/compile_success_empty/derive_impl/src/main.nr @@ -0,0 +1,44 @@ +comptime fn derive_default(typ: TypeDefinition) -> Quoted { + let generics: [Quoted] = typ.generics(); + assert_eq( + generics.len(), 0, "derive_default: Deriving Default on generic types is currently unimplemented" + ); + + let type_name = typ.as_type(); + let fields = typ.fields(); + + let fields = join(make_field_exprs(fields)); + + quote { + impl Default for $type_name { + fn default() -> Self { + Self { $fields } + } + } + } +} + +#[derive_default] +struct Foo { + x: Field, + y: u32, +} + +comptime fn make_field_exprs(fields: [(Quoted, Quoted)]) -> [Quoted] { + let mut result = &[]; + for my_field in fields { + let name = my_field.0; + result = result.push_back(quote { $name: Default::default(), }); + } + result +} + +comptime fn join(slice: [Quoted]) -> Quoted { + let mut result = quote {}; + for elem in slice { + result = quote { $result $elem }; + } + result +} + +fn main() {}