Skip to content
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
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ impl<'context> Elaborator<'context> {
}
}

pub(super) fn type_check_variable(
pub(crate) fn type_check_variable(
&mut self,
ident: HirIdent,
expr_id: ExprId,
Expand Down
22 changes: 21 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::{
},
hir_def::{
self,
expr::{HirExpression, HirLiteral},
expr::{HirExpression, HirIdent, HirLiteral},
function::FunctionBody,
},
node_interner::{DefinitionKind, NodeInterner, TraitImplKind},
Expand Down Expand Up @@ -121,6 +121,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"fmtstr_quoted_contents" => fmtstr_quoted_contents(interner, arguments, location),
"fresh_type_variable" => fresh_type_variable(interner),
"function_def_add_attribute" => function_def_add_attribute(self, arguments, location),
"function_def_as_typed_expr" => function_def_as_typed_expr(self, arguments, location),
"function_def_body" => function_def_body(interner, arguments, location),
"function_def_eq" => function_def_eq(arguments, location),
"function_def_has_named_attribute" => {
Expand Down Expand Up @@ -2423,6 +2424,25 @@ fn function_def_add_attribute(
Ok(Value::Unit)
}

// fn as_typed_expr(self) -> TypedExpr
fn function_def_as_typed_expr(
interpreter: &mut Interpreter,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let func_id = get_function_def(self_argument)?;
let definition_id = interpreter.elaborator.interner.function_definition_id(func_id);
let hir_ident = HirIdent::non_trait_method(definition_id, location);
let generics = None;
let hir_expr = HirExpression::Ident(hir_ident.clone(), generics.clone());
let expr_id = interpreter.elaborator.interner.push_expr(hir_expr);
interpreter.elaborator.interner.push_expr_location(expr_id, location.span, location.file);
let typ = interpreter.elaborator.type_check_variable(hir_ident, expr_id, generics);
interpreter.elaborator.interner.push_expr_type(expr_id, typ);
Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id)))
}

// fn body(self) -> Expr
fn function_def_body(
interner: &NodeInterner,
Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@
Value::Expr(ExprValue::Statement(statement))
}

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

Check warning on line 102 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))

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lvaue)
}

pub(crate) fn pattern(pattern: Pattern) -> Self {
Expand Down Expand Up @@ -495,6 +495,7 @@
Value::UnresolvedType(typ) => {
Token::InternedUnresolvedTypeData(interner.push_unresolved_type_data(typ))
}
Value::TypedExpr(TypedExpr::ExprId(expr_id)) => Token::UnquoteMarker(expr_id),
Value::U1(bool) => Token::Bool(bool),
Value::U8(value) => Token::Int((value as u128).into()),
Value::U16(value) => Token::Int((value as u128).into()),
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pub enum Token {
InternedLValue(InternedExpressionKind),
/// A reference to an interned `UnresolvedTypeData`.
InternedUnresolvedTypeData(InternedUnresolvedTypeData),
/// A reference to an interned `Patter`.
/// A reference to an interned `Pattern`.
InternedPattern(InternedPattern),
/// <
Less,
Expand Down
11 changes: 11 additions & 0 deletions docs/docs/noir/standard_library/meta/function_def.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ Adds an attribute to the function. This is only valid
on functions in the current crate which have not yet been resolved.
This means any functions called at compile-time are invalid targets for this method.

### as_typed_expr

#include_code as_typed_expr noir_stdlib/src/meta/function_def.nr rust

Returns this function as a `TypedExpr`, which can be unquoted. For example:

```rust
let typed_expr = some_function.as_typed_expr();
let _ = quote { $typed_expr(1, 2, 3); };
```

### body

#include_code body noir_stdlib/src/meta/function_def.nr rust
Expand Down
5 changes: 5 additions & 0 deletions noir_stdlib/src/meta/function_def.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ impl FunctionDefinition {
pub comptime fn add_attribute<let N: u32>(self, attribute: str<N>) {}
// docs:end:add_attribute

#[builtin(function_def_as_typed_expr)]
// docs:start:as_typed_expr
pub comptime fn as_typed_expr(self) -> TypedExpr {}
// docs:end:as_typed_expr

#[builtin(function_def_body)]
// docs:start:body
pub comptime fn body(self) -> Expr {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,106 @@ mod foo {
assert(!f.is_unconstrained());
}
}

mod test_as_typed_expr_1 {
#![foo]

pub fn method<T>(x: T) -> T {
x
}

comptime fn foo(module: Module) -> Quoted {
let method = module.functions().filter(|f| f.name() == quote { method })[0];
let func = method.as_typed_expr();
quote {
pub fn bar() -> i32 {
$func(1)
}
}
}

pub fn test() {
comptime {
assert_eq(bar(), 1);
}
}
}

mod test_as_typed_expr_2 {
#![foo]

unconstrained fn method<T, let N: u32>(xs: [T; N]) -> u32 {
xs.len()
}

comptime fn foo(module: Module) -> Quoted {
let method = module.functions().filter(|f| f.name() == quote { method })[0];
let func = method.as_typed_expr();
quote {
pub fn bar() -> u32 {
/// Safety: test program
unsafe { $func([1, 2, 3, 0]) }
}
}
}

pub fn test() {
comptime {
assert_eq(bar(), 4);
}
}
}

mod test_as_typed_expr_3 {
#![foo]

pub comptime fn method<T, U, let N: u32>(xs_ys: ([T; N], U)) -> u32 {
let (xs, _ys) = xs_ys;
xs.len()
}

comptime fn foo(module: Module) -> Quoted {
let method = module.functions().filter(|f| f.name() == quote { method })[0];
let func = method.as_typed_expr();
quote {
pub fn bar() -> u32 {
/// Safety: test program
comptime { $func(([1, 2, 3, 0], "a")) }
}
}
}

pub fn test() {
comptime {
assert_eq(bar(), 4);
}
}
}

mod test_as_typed_expr_4 {
comptime fn foo(f: TypedExpr) -> Quoted {
quote {
$f()
}
}

fn bar() -> Field {
1
}

fn baz() -> Field {
let x: Field = comptime {
let bar_q = quote {
bar
};
foo(bar_q.as_expr().unwrap().resolve(Option::none()))
};
x
}

pub fn test() {
comptime {
assert_eq(baz(), 1);
}
}
}
Loading