Skip to content

Commit

Permalink
Merge 917b381 into de0f8ee
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Aug 26, 2024
2 parents de0f8ee + 917b381 commit 6b69359
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 12 deletions.
45 changes: 39 additions & 6 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use builtin_helpers::{
block_expression_to_value, check_argument_count, check_function_not_yet_resolved,
check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_function_def,
get_module, get_quoted, get_slice, get_struct, get_trait_constraint, get_trait_def,
get_trait_impl, get_tuple, get_type, get_u32, hir_pattern_to_tokens, mutate_func_meta_type,
parse, parse_tokens, replace_func_meta_parameters, replace_func_meta_return_type,
get_trait_impl, get_tuple, get_type, get_u32, get_unresolved_type, hir_pattern_to_tokens,
mutate_func_meta_type, parse, parse_tokens, replace_func_meta_parameters,
replace_func_meta_return_type,
};
use im::Vector;
use iter_extended::{try_vecmap, vecmap};
Expand Down Expand Up @@ -53,6 +54,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"array_len" => array_len(interner, arguments, location),
"as_slice" => as_slice(interner, arguments, location),
"expr_as_array" => expr_as_array(arguments, return_type, location),
"expr_as_assign" => expr_as_assign(arguments, return_type, location),
"expr_as_binary_op" => expr_as_binary_op(arguments, return_type, location),
"expr_as_block" => expr_as_block(arguments, return_type, location),
"expr_as_bool" => expr_as_bool(arguments, return_type, location),
Expand Down Expand Up @@ -132,6 +134,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"type_is_bool" => type_is_bool(arguments, location),
"type_is_field" => type_is_field(arguments, location),
"type_of" => type_of(arguments, location),
"unresolved_type_is_field" => unresolved_type_is_field(arguments, location),
"zeroed" => zeroed(return_type),
_ => {
let item = format!("Comptime evaluation for builtin function {name}");
Expand Down Expand Up @@ -705,6 +708,16 @@ fn trait_impl_trait_generic_args(
Ok(Value::Slice(trait_generics, slice_type))
}

// fn is_field(self) -> bool
fn unresolved_type_is_field(
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let typ = get_unresolved_type(self_argument)?;
Ok(Value::Bool(matches!(typ, UnresolvedTypeData::FieldElement)))
}

// fn zeroed<T>() -> T
fn zeroed(return_type: Type) -> IResult<Value> {
match return_type {
Expand Down Expand Up @@ -806,6 +819,23 @@ fn expr_as_array(
})
}

// fn as_assign(self) -> Option<(Expr, Expr)>
fn expr_as_assign(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
expr_as(arguments, return_type, location, |expr| {
if let ExprValue::Statement(StatementKind::Assign(assign)) = expr {
let lhs = Value::lvalue(assign.lvalue);
let rhs = Value::expression(assign.expression.kind);
Some(Value::Tuple(vec![lhs, rhs]))
} else {
None
}
})
}

// fn as_binary_op(self) -> Option<(Expr, BinaryOp, Expr)>
fn expr_as_binary_op(
arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -1010,16 +1040,19 @@ fn expr_as_member_access(
return_type: Type,
location: Location,
) -> IResult<Value> {
expr_as(arguments, return_type, location, |expr| {
if let ExprValue::Expression(ExpressionKind::MemberAccess(member_access)) = expr {
expr_as(arguments, return_type, location, |expr| match expr {
ExprValue::Expression(ExpressionKind::MemberAccess(member_access)) => {
let tokens = Rc::new(vec![Token::Ident(member_access.rhs.0.contents.clone())]);
Some(Value::Tuple(vec![
Value::expression(member_access.lhs.kind),
Value::Quoted(tokens),
]))
} else {
None
}
ExprValue::LValue(crate::ast::LValue::MemberAccess { object, field_name, span: _ }) => {
let tokens = Rc::new(vec![Token::Ident(field_name.0.contents.clone())]);
Some(Value::Tuple(vec![Value::lvalue(*object), Value::Quoted(tokens)]))
}
_ => None,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use acvm::FieldElement;
use noirc_errors::Location;

use crate::{
ast::{BlockExpression, IntegerBitSize, Signedness},
ast::{BlockExpression, IntegerBitSize, Signedness, UnresolvedTypeData},
hir::{
comptime::{
errors::IResult,
Expand Down Expand Up @@ -207,6 +207,15 @@ pub(crate) fn get_quoted((value, location): (Value, Location)) -> IResult<Rc<Vec
}
}

pub(crate) fn get_unresolved_type(
(value, location): (Value, Location),
) -> IResult<UnresolvedTypeData> {
match value {
Value::UnresolvedType(typ) => Ok(typ),
value => type_mismatch(value, Type::Quoted(QuotedType::UnresolvedType), location),
}
}

fn type_mismatch<T>(value: Value, expected: Type, location: Location) -> IResult<T> {
let actual = value.get_type().into_owned();
Err(InterpreterError::TypeMismatch { expected, actual, location })
Expand Down
13 changes: 10 additions & 3 deletions compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use strum_macros::Display;

use crate::{
ast::{
ArrayLiteral, BlockExpression, ConstructorExpression, Ident, IntegerBitSize, Signedness,
Statement, StatementKind, UnresolvedTypeData,
ArrayLiteral, BlockExpression, ConstructorExpression, Ident, IntegerBitSize, LValue,
Signedness, Statement, StatementKind, UnresolvedTypeData,
},
hir::{def_map::ModuleId, type_check::generics::TraitGenerics},
hir_def::{
Expand Down Expand Up @@ -73,6 +73,7 @@ pub enum Value {
pub enum ExprValue {
Expression(ExpressionKind),
Statement(StatementKind),
LValue(LValue),
}

impl Value {
Expand All @@ -84,6 +85,10 @@ impl Value {
Value::Expr(ExprValue::Statement(statement))
}

pub(crate) fn lvalue(lvaue: LValue) -> Self {
Value::Expr(ExprValue::LValue(lvaue))
}

pub(crate) fn get_type(&self) -> Cow<Type> {
Cow::Owned(match self {
Value::Unit => Type::Unit,
Expand Down Expand Up @@ -256,7 +261,8 @@ impl Value {
statements: vec![Statement { kind: statement, span: location.span }],
})
}
Value::Pointer(..)
Value::Expr(ExprValue::LValue(_))
| Value::Pointer(..)
| Value::StructDefinition(_)
| Value::TraitConstraint(..)
| Value::TraitDefinition(_)
Expand Down Expand Up @@ -593,6 +599,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> {
Value::Type(typ) => write!(f, "{}", typ),
Value::Expr(ExprValue::Expression(expr)) => write!(f, "{}", expr),
Value::Expr(ExprValue::Statement(statement)) => write!(f, "{}", statement),
Value::Expr(ExprValue::LValue(lvalue)) => write!(f, "{}", lvalue),
Value::UnresolvedType(typ) => write!(f, "{}", typ),
}
}
Expand Down
1 change: 1 addition & 0 deletions docs/docs/noir/concepts/comptime.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ The following is an incomplete list of some `comptime` types along with some use
- `fn fields(self) -> [(Quoted, Type)]`
- Return the name and type of each field
- `TraitConstraint`: A trait constraint such as `From<Field>`
- `UnresolvedType`: A syntactic notation that refers to a Noir type that hasn't been resolved yet

There are many more functions available by exploring the `std::meta` module and its submodules.
Using these methods is the key to writing powerful metaprogramming libraries.
Expand Down
7 changes: 7 additions & 0 deletions docs/docs/noir/standard_library/meta/expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ title: Expr

If this expression is an array, this returns a slice of each element in the array.

### as_assign

#include_code as_assign noir_stdlib/src/meta/expr.nr rust

If this expression is an assignment, this returns a tuple with the left hand side
and right hand side in order.

### as_integer

#include_code as_integer noir_stdlib/src/meta/expr.nr rust
Expand Down
13 changes: 13 additions & 0 deletions docs/docs/noir/standard_library/meta/unresolved_type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: UnresolvedType
---

`std::meta::unresolved_type` contains methods on the built-in `UnresolvedType` type for the syntax of types.

## Methods

### is_field

#include_code is_field noir_stdlib/src/meta/unresolved_type.nr rust

Returns true if this type refers to the Field type.
31 changes: 30 additions & 1 deletion noir_stdlib/src/meta/expr.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ impl Expr {
fn as_array(self) -> Option<[Expr]> {}
// docs:end:as_array

#[builtin(expr_as_assign)]
// docs:start:as_assign
fn as_assign(self) -> Option<(Expr, Expr)> {}
// docs:end:as_assign

#[builtin(expr_as_integer)]
// docs:start:as_integer
fn as_integer(self) -> Option<(Field, bool)> {}
Expand Down Expand Up @@ -119,6 +124,17 @@ mod tests {
}
}

#[test]
fn test_expr_as_assign() {
comptime
{
let expr = quote { { a = 1; } }.as_expr().unwrap();
let exprs = expr.as_block().unwrap();
let (_lhs, rhs) = exprs[0].as_assign().unwrap();
assert_eq(rhs.as_integer().unwrap(), (1, false));
}
}

#[test]
fn test_expr_as_block() {
comptime
Expand Down Expand Up @@ -188,8 +204,9 @@ mod tests {
comptime
{
let expr = quote { 1 as Field }.as_expr().unwrap();
let (expr, _typ) = expr.as_cast().unwrap();
let (expr, typ) = expr.as_cast().unwrap();
assert_eq(expr.as_integer().unwrap(), (1, false));
assert(typ.is_field());
}
}

Expand Down Expand Up @@ -264,6 +281,18 @@ mod tests {
}
}

#[test]
fn test_expr_as_member_access_with_an_lvalue() {
comptime
{
let expr = quote { { foo.bar = 1; } }.as_expr().unwrap();
let exprs = expr.as_block().unwrap();
let (lhs, _rhs) = exprs[0].as_assign().unwrap();
let (_, name) = lhs.as_member_access().unwrap();
assert_eq(name, quote { bar });
}
}

#[test]
fn test_expr_as_repeated_element_array() {
comptime
Expand Down
3 changes: 2 additions & 1 deletion noir_stdlib/src/meta/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod trait_def;
mod trait_impl;
mod typ;
mod quoted;
mod unresolved_type;

/// Calling unquote as a macro (via `unquote!(arg)`) will unquote
/// its argument. Since this is the effect `!` already does, `unquote`
Expand Down Expand Up @@ -163,7 +164,7 @@ mod tests {
}
// docs:end:annotation-arguments-example

// docs:end:annotation-varargs-example
// docs:start:annotation-varargs-example
#[assert_three_args(1, 2, 3)]
struct MyOtherStruct { my_other_field: u32 }

Expand Down
6 changes: 6 additions & 0 deletions noir_stdlib/src/meta/unresolved_type.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
impl UnresolvedType {
#[builtin(unresolved_type_is_field)]
// docs:start:is_field
fn is_field(self) -> bool {}
// docs:end:is_field
}

0 comments on commit 6b69359

Please sign in to comment.