Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add UnresolvedType::is_field and Expr::as_assign #5804

Merged
merged 6 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
"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 @@
"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 @@ -409,7 +412,7 @@
let argument = check_one_argument(arguments, location)?;
let typ = parse(argument, parser::parse_type(), "a type")?;
let typ =
interpreter.elaborate_item(interpreter.current_function, |elab| elab.resolve_type(typ));

Check warning on line 415 in compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elab)

Check warning on line 415 in compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elab)
Ok(Value::Type(typ))
}

Expand Down Expand Up @@ -705,6 +708,16 @@
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 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 @@
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 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 ExprValue {
Expression(ExpressionKind),
Statement(StatementKind),
LValue(LValue),
}

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

pub(crate) fn lvalue(lvaue: LValue) -> Self {

Check warning on line 88 in compiler/noirc_frontend/src/hir/comptime/value.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lvaue)
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 @@
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 @@
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
jfecher marked this conversation as resolved.
Show resolved Hide resolved
#[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
}
Loading