Skip to content

Commit

Permalink
fix: Implement interpretation of member access on tuples (#5311)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves <!-- Link to GitHub Issue -->

## Summary\*

Fixes an issue in the interpreter where the interpreter would error for
member access expressions on tuples. This prevented e.g. `my_tuple.0`.

## Additional Context



## 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.

---------

Co-authored-by: Tom French <[email protected]>
  • Loading branch information
jfecher and TomAFrench authored Jun 24, 2024
1 parent 32f66f3 commit b94662e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
12 changes: 12 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,18 @@ impl<'a> Interpreter<'a> {
fn evaluate_access(&mut self, access: HirMemberAccess, id: ExprId) -> IResult<Value> {
let (fields, struct_type) = match self.evaluate(access.lhs)? {
Value::Struct(fields, typ) => (fields, typ),
Value::Tuple(fields) => {
let (fields, field_types): (HashMap<Rc<String>, Value>, Vec<Type>) = fields
.into_iter()
.enumerate()
.map(|(i, field)| {
let field_type = field.get_type().into_owned();
let key_val_pair = (Rc::new(i.to_string()), field);
(key_val_pair, field_type)
})
.unzip();
(fields, Type::Tuple(field_types))
}
value => {
let location = self.interner.expr_location(&id);
return Err(InterpreterError::NonTupleOrStructInMemberAccess { value, location });
Expand Down
15 changes: 15 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -48,6 +49,20 @@ fn as_slice(mut arguments: Vec<(Value, Location)>) -> IResult<Value> {
}
}

fn slice_push_back(mut arguments: Vec<(Value, Location)>) -> IResult<Value> {
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,
Expand Down
7 changes: 7 additions & 0 deletions test_programs/compile_success_empty/derive_impl/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "derive_impl"
type = "bin"
authors = [""]
compiler_version = ">=0.30.0"

[dependencies]
44 changes: 44 additions & 0 deletions test_programs/compile_success_empty/derive_impl/src/main.nr
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit b94662e

Please sign in to comment.