Skip to content

Commit

Permalink
feat: Implement closures in the comptime interpreter (noir-lang/noir#…
Browse files Browse the repository at this point in the history
…5682)

feat: add `FunctionDefinition::parameters`, `FunctionDefinition::return_type` and `impl Eq for Quoted` (noir-lang/noir#5681)
feat: add `Type::as_struct` (noir-lang/noir#5680)
feat: LSP hover now includes "Go to" links (noir-lang/noir#5677)
feat: add `Type` methods: `as_tuple`, `as_slice`, `as_array`, `as_constant`, `is_bool` (noir-lang/noir#5678)
fix: Derive generic types (noir-lang/noir#5674)
feat: Add a limited form of arithmetic on generics (noir-lang/noir#5625)
feat: add `Type::is_field` and `Type::as_integer` (noir-lang/noir#5670)
fix: Fix where clause issue in items generated from attributes (noir-lang/noir#5673)
feat(noir_js): Expose UltraHonk and integration tests (noir-lang/noir#5656)
fix: workaround from_slice with nested slices (noir-lang/noir#5648)
fix: Switch verify proof to arrays (noir-lang/noir#5664)
feat: Resolve arguments to attributes (noir-lang/noir#5649)
fix: Elaborate struct & trait annotations in the correct module (noir-lang/noir#5643)
fix: let a trait impl that relies on another trait work (noir-lang/noir#5646)
  • Loading branch information
AztecBot committed Aug 6, 2024
2 parents 46e8418 + 67025e0 commit 9b76740
Show file tree
Hide file tree
Showing 14 changed files with 463 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .noir-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d466d491ea50b495be7d5a45a8c3d85771f9b1c0
9e2a3232c8849f19732472e75840717b8b95a4a9
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
fn call_closure(
&mut self,
closure: HirLambda,
// TODO: How to define environment here?
_environment: Vec<Value>,
environment: Vec<Value>,
arguments: Vec<(Value, Location)>,
call_location: Location,
) -> IResult<Value> {
Expand All @@ -246,6 +245,10 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
self.define_pattern(parameter, typ, argument, arg_location)?;
}

for (param, arg) in closure.captures.into_iter().zip(environment) {
self.define(param.ident.id, arg);
}

let result = self.evaluate(closure.body)?;

self.exit_function(previous_state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ use std::{
};

use acvm::{AcirField, FieldElement};
use builtin_helpers::{
check_argument_count, check_one_argument, check_three_arguments, check_two_arguments,
get_function_def, get_quoted, get_slice, get_trait_constraint, get_trait_def, get_type,
get_u32, hir_pattern_to_tokens,
};
use chumsky::Parser;
use iter_extended::{try_vecmap, vecmap};
use noirc_errors::Location;
Expand All @@ -13,14 +18,15 @@ use crate::{
ast::IntegerBitSize,
hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value},
macros_api::{NodeInterner, Signedness},
node_interner::TraitId,
parser,
token::Token,
QuotedType, Shared, Type,
};

use super::Interpreter;

pub(crate) mod builtin_helpers;

impl<'local, 'context> Interpreter<'local, 'context> {
pub(super) fn call_builtin(
&mut self,
Expand All @@ -34,11 +40,16 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"array_len" => array_len(interner, arguments, location),
"as_slice" => as_slice(interner, arguments, location),
"is_unconstrained" => Ok(Value::Bool(true)),
"function_def_parameters" => function_def_parameters(interner, arguments, location),
"function_def_return_type" => function_def_return_type(interner, arguments, location),
"modulus_be_bits" => modulus_be_bits(interner, arguments, location),
"modulus_be_bytes" => modulus_be_bytes(interner, arguments, location),
"modulus_le_bits" => modulus_le_bits(interner, arguments, location),
"modulus_le_bytes" => modulus_le_bytes(interner, arguments, location),
"modulus_num_bits" => modulus_num_bits(interner, arguments, location),
"quoted_as_trait_constraint" => quoted_as_trait_constraint(self, arguments, location),
"quoted_as_type" => quoted_as_type(self, arguments, location),
"quoted_eq" => quoted_eq(arguments, location),
"slice_insert" => slice_insert(interner, arguments, location),
"slice_pop_back" => slice_pop_back(interner, arguments, location),
"slice_pop_front" => slice_pop_front(interner, arguments, location),
Expand All @@ -55,12 +66,11 @@ impl<'local, 'context> Interpreter<'local, 'context> {
}
"trait_def_eq" => trait_def_eq(interner, arguments, location),
"trait_def_hash" => trait_def_hash(interner, arguments, location),
"quoted_as_trait_constraint" => quoted_as_trait_constraint(self, arguments, location),
"quoted_as_type" => quoted_as_type(self, arguments, location),
"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_slice" => type_as_slice(arguments, return_type, location),
"type_as_struct" => type_as_struct(arguments, return_type, location),
"type_as_tuple" => type_as_tuple(arguments, return_type, location),
"type_eq" => type_eq(arguments, location),
"type_is_bool" => type_is_bool(arguments, location),
Expand All @@ -75,19 +85,6 @@ impl<'local, 'context> Interpreter<'local, 'context> {
}
}

pub(super) fn check_argument_count(
expected: usize,
arguments: &[(Value, Location)],
location: Location,
) -> IResult<()> {
if arguments.len() == expected {
Ok(())
} else {
let actual = arguments.len();
Err(InterpreterError::ArgumentCountMismatch { expected, actual, location })
}
}

pub(super) fn check_one_argument(
mut arguments: Vec<(Value, Location)>,
location: Location,
Expand Down Expand Up @@ -126,103 +123,6 @@ fn failing_constraint<T>(message: impl Into<String>, location: Location) -> IRes
Err(InterpreterError::FailingConstraint { message: Some(message.into()), location })
}

pub(super) fn get_array(
interner: &NodeInterner,
value: Value,
location: Location,
) -> IResult<(im::Vector<Value>, Type)> {
match value {
Value::Array(values, typ) => Ok((values, typ)),
value => {
let type_var = Box::new(interner.next_type_variable());
let expected = Type::Array(type_var.clone(), type_var);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

fn get_slice(
interner: &NodeInterner,
value: Value,
location: Location,
) -> IResult<(im::Vector<Value>, Type)> {
match value {
Value::Slice(values, typ) => Ok((values, typ)),
value => {
let type_var = Box::new(interner.next_type_variable());
let expected = Type::Slice(type_var);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

pub(super) fn get_field(value: Value, location: Location) -> IResult<FieldElement> {
match value {
Value::Field(value) => Ok(value),
value => {
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected: Type::FieldElement, actual, location })
}
}
}

pub(super) fn get_u32(value: Value, location: Location) -> IResult<u32> {
match value {
Value::U32(value) => Ok(value),
value => {
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

fn get_trait_constraint(value: Value, location: Location) -> IResult<(TraitId, Vec<Type>)> {
match value {
Value::TraitConstraint(trait_id, generics) => Ok((trait_id, generics)),
value => {
let expected = Type::Quoted(QuotedType::TraitConstraint);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

fn get_trait_def(value: Value, location: Location) -> IResult<TraitId> {
match value {
Value::TraitDefinition(id) => Ok(id),
value => {
let expected = Type::Quoted(QuotedType::TraitDefinition);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

fn get_type(value: Value, location: Location) -> IResult<Type> {
match value {
Value::Type(typ) => Ok(typ),
value => {
let expected = Type::Quoted(QuotedType::Type);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

fn get_quoted(value: Value, location: Location) -> IResult<Rc<Vec<Token>>> {
match value {
Value::Quoted(tokens) => Ok(tokens),
value => {
let expected = Type::Quoted(QuotedType::Quoted);
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
}
}
}

fn array_len(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -550,6 +450,27 @@ fn type_as_slice(
})
}

// fn as_struct(self) -> Option<(StructDefinition, [Type])>
fn type_as_struct(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
type_as(arguments, return_type, location, |typ| {
if let Type::Struct(struct_type, generics) = typ {
Some(Value::Tuple(vec![
Value::StructDefinition(struct_type.borrow().id),
Value::Slice(
generics.into_iter().map(Value::Type).collect(),
Type::Slice(Box::new(Type::Quoted(QuotedType::Type))),
),
]))
} else {
None
}
})
}

// fn as_tuple(self) -> Option<[Type]>
fn type_as_tuple(
arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -593,6 +514,9 @@ where
fn type_eq(arguments: Vec<(Value, Location)>, location: Location) -> IResult<Value> {
let (self_type, other_type) = check_two_arguments(arguments, location)?;

let self_type = get_type(self_type, location)?;
let other_type = get_type(other_type, location)?;

Ok(Value::Bool(self_type == other_type))
}

Expand Down Expand Up @@ -762,6 +686,47 @@ fn zeroed(return_type: Type) -> IResult<Value> {
}
}

// fn parameters(self) -> [(Quoted, Type)]
fn function_def_parameters(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let func_id = get_function_def(self_argument, location)?;
let func_meta = interner.function_meta(&func_id);

let parameters = func_meta
.parameters
.iter()
.map(|(hir_pattern, typ, _visibility)| {
let name = Value::Quoted(Rc::new(hir_pattern_to_tokens(interner, hir_pattern)));
let typ = Value::Type(typ.clone());
Value::Tuple(vec![name, typ])
})
.collect();

let typ = Type::Slice(Box::new(Type::Tuple(vec![
Type::Quoted(QuotedType::Quoted),
Type::Quoted(QuotedType::Type),
])));

Ok(Value::Slice(parameters, typ))
}

// fn return_type(self) -> Type
fn function_def_return_type(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let func_id = get_function_def(self_argument, location)?;
let func_meta = interner.function_meta(&func_id);

Ok(Value::Type(func_meta.return_type().follow_bindings()))
}

fn modulus_be_bits(
_interner: &mut NodeInterner,
arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -826,6 +791,16 @@ fn modulus_num_bits(
Ok(Value::U64(bits))
}

// fn quoted_eq(_first: Quoted, _second: Quoted) -> bool
fn quoted_eq(arguments: Vec<(Value, Location)>, location: Location) -> IResult<Value> {
let (self_value, other_value) = check_two_arguments(arguments, location)?;

let self_quoted = get_quoted(self_value, location)?;
let other_quoted = get_quoted(other_value, location)?;

Ok(Value::Bool(self_quoted == other_quoted))
}

fn trait_def_as_trait_constraint(
interner: &mut NodeInterner,
arguments: Vec<(Value, Location)>,
Expand Down
Loading

0 comments on commit 9b76740

Please sign in to comment.