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/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl<'context> Elaborator<'context> {
}
}

pub(super) fn elaborate_statement(&mut self, statement: Statement) -> (StmtId, Type) {
pub(crate) fn elaborate_statement(&mut self, statement: Statement) -> (StmtId, Type) {
let span = statement.span;
let (hir_statement, typ) = self.elaborate_statement_value(statement);
let id = self.interner.push_stmt(hir_statement);
Expand Down
80 changes: 72 additions & 8 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +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_field,
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, get_unresolved_type,
hir_pattern_to_tokens, mutate_func_meta_type, parse, replace_func_meta_parameters,
replace_func_meta_return_type,
get_trait_def, get_trait_impl, get_tuple, get_type, get_typed_expr, get_u32,
get_unresolved_type, hir_pattern_to_tokens, mutate_func_meta_type, parse,
replace_func_meta_parameters, replace_func_meta_return_type,
};
use chumsky::{prelude::choice, Parser};
use im::Vector;
Expand All @@ -25,7 +25,11 @@ use crate::{
FunctionReturnType, IntegerBitSize, LValue, Literal, Statement, StatementKind, UnaryOp,
UnresolvedType, UnresolvedTypeData, Visibility,
},
hir::comptime::{errors::IResult, value::ExprValue, InterpreterError, Value},
hir::comptime::{
errors::IResult,
value::{ExprValue, TypedExpr},
InterpreterError, Value,
},
hir_def::function::FunctionBody,
macros_api::{HirExpression, HirLiteral, ModuleDefId, NodeInterner, Signedness},
node_interner::{DefinitionKind, TraitImplKind},
Expand Down Expand Up @@ -87,6 +91,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"expr_has_semicolon" => expr_has_semicolon(interner, arguments, location),
"expr_is_break" => expr_is_break(interner, arguments, location),
"expr_is_continue" => expr_is_continue(interner, arguments, location),
"expr_resolve" => expr_resolve(self, arguments, location),
"is_unconstrained" => Ok(Value::Bool(true)),
"function_def_body" => function_def_body(interner, arguments, location),
"function_def_name" => function_def_name(interner, arguments, location),
Expand Down Expand Up @@ -145,6 +150,9 @@ 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),
"typed_expr_as_function_definition" => {
typed_expr_as_function_definition(interner, arguments, return_type, location)
}
"unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location),
"zeroed" => zeroed(return_type),
_ => {
Expand Down Expand Up @@ -763,6 +771,23 @@ fn trait_impl_trait_generic_args(
Ok(Value::Slice(trait_generics, slice_type))
}

fn typed_expr_as_function_definition(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let typed_expr = get_typed_expr(self_argument)?;
let option_value = if let TypedExpr::ExprId(expr_id) = typed_expr {
let func_id = interner.lookup_function_from_expr(&expr_id);
func_id.map(Value::FunctionDefinition)
} else {
None
};
option(return_type, option_value)
}

// fn is_field(self) -> bool
fn unresolved_type_is_field(
interner: &NodeInterner,
Expand Down Expand Up @@ -1380,7 +1405,48 @@ where
F: FnOnce(ExprValue) -> Option<Value>,
{
let self_argument = check_one_argument(arguments, location)?;
let mut expr_value = get_expr(interner, self_argument)?;
let expr_value = get_expr(interner, self_argument)?;
let expr_value = unwrap_expr_value(interner, expr_value);

let option_value = f(expr_value);
option(return_type, option_value)
}

// fn resolve(self) -> TypedExpr
fn expr_resolve(
interpreter: &mut Interpreter,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let self_argument_location = self_argument.1;
let expr_value = get_expr(interpreter.elaborator.interner, self_argument)?;
let expr_value = unwrap_expr_value(interpreter.elaborator.interner, expr_value);

let value =
interpreter.elaborate_item(interpreter.current_function, |elaborator| match expr_value {
ExprValue::Expression(expression_kind) => {
let expr = Expression { kind: expression_kind, span: self_argument_location.span };
let (expr_id, _) = elaborator.elaborate_expression(expr);
Value::TypedExpr(TypedExpr::ExprId(expr_id))
}
ExprValue::Statement(statement_kind) => {
let statement =
Statement { kind: statement_kind, span: self_argument_location.span };
let (stmt_id, _) = elaborator.elaborate_statement(statement);
Value::TypedExpr(TypedExpr::StmtId(stmt_id))
}
ExprValue::LValue(lvalue) => {
let expr = lvalue.as_expression();
let (expr_id, _) = elaborator.elaborate_expression(expr);
Value::TypedExpr(TypedExpr::ExprId(expr_id))
}
});

Ok(value)
}

fn unwrap_expr_value(interner: &NodeInterner, mut expr_value: ExprValue) -> ExprValue {
loop {
match expr_value {
ExprValue::Expression(ExpressionKind::Parenthesized(expression)) => {
Expand All @@ -1402,9 +1468,7 @@ where
_ => break,
}
}

let option_value = f(expr_value);
option(return_type, option_value)
expr_value
}

// fn body(self) -> Expr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
hir::{
comptime::{
errors::IResult,
value::{add_token_spans, ExprValue},
value::{add_token_spans, ExprValue, TypedExpr},
Interpreter, InterpreterError, Value,
},
def_map::ModuleId,
Expand Down Expand Up @@ -227,6 +227,13 @@ pub(crate) fn get_type((value, location): (Value, Location)) -> IResult<Type> {
}
}

pub(crate) fn get_typed_expr((value, location): (Value, Location)) -> IResult<TypedExpr> {
match value {
Value::TypedExpr(typed_expr) => Ok(typed_expr),
value => type_mismatch(value, Type::Quoted(QuotedType::TypedExpr), location),
}
}

pub(crate) fn get_quoted((value, location): (Value, Location)) -> IResult<Rc<Vec<Token>>> {
match value {
Value::Quoted(tokens) => Ok(tokens),
Expand Down
18 changes: 15 additions & 3 deletions compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
Expression, ExpressionKind, HirExpression, HirLiteral, Literal, NodeInterner, Path,
StructId,
},
node_interner::{ExprId, FuncId, TraitId, TraitImplId},
node_interner::{ExprId, FuncId, StmtId, TraitId, TraitImplId},
parser::{self, NoirParser, TopLevelStatement},
token::{SpannedToken, Token, Tokens},
QuotedType, Shared, Type, TypeBindings,
Expand Down Expand Up @@ -69,6 +69,7 @@ pub enum Value {
Type(Type),
Zeroed(Type),
Expr(ExprValue),
TypedExpr(TypedExpr),
UnresolvedType(UnresolvedTypeData),
}

Expand All @@ -79,6 +80,12 @@ pub enum ExprValue {
LValue(LValue),
}

#[derive(Debug, Clone, PartialEq, Eq, Display)]
pub enum TypedExpr {
ExprId(ExprId),
StmtId(StmtId),
}

impl Value {
pub(crate) fn expression(expr: ExpressionKind) -> Self {
Value::Expr(ExprValue::Expression(expr))
Expand Down Expand Up @@ -137,6 +144,7 @@ impl Value {
Value::Type(_) => Type::Quoted(QuotedType::Type),
Value::Zeroed(typ) => return Cow::Borrowed(typ),
Value::Expr(_) => Type::Quoted(QuotedType::Expr),
Value::TypedExpr(_) => Type::Quoted(QuotedType::TypedExpr),
Value::UnresolvedType(_) => Type::Quoted(QuotedType::UnresolvedType),
})
}
Expand Down Expand Up @@ -264,7 +272,8 @@ impl Value {
statements: vec![Statement { kind: statement, span: location.span }],
})
}
Value::Expr(ExprValue::LValue(_))
Value::Expr(ExprValue::LValue(lvalue)) => lvalue.as_expression().kind,
Value::TypedExpr(..)
| Value::Pointer(..)
| Value::StructDefinition(_)
| Value::TraitConstraint(..)
Expand Down Expand Up @@ -389,7 +398,9 @@ impl Value {
HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements)))
}
Value::Quoted(tokens) => HirExpression::Unquote(add_token_spans(tokens, location.span)),
Value::Expr(..)
Value::TypedExpr(TypedExpr::ExprId(expr_id)) => interner.expression(&expr_id),
Value::TypedExpr(TypedExpr::StmtId(..))
| Value::Expr(..)
| Value::Pointer(..)
| Value::StructDefinition(_)
| Value::TraitConstraint(..)
Expand Down Expand Up @@ -621,6 +632,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> {
Value::Expr(ExprValue::LValue(lvalue)) => {
write!(f, "{}", remove_interned_in_lvalue(self.interner, lvalue.clone()))
}
Value::TypedExpr(_) => write!(f, "(typed expr)"),
Value::UnresolvedType(typ) => {
if let UnresolvedTypeData::Interned(id) = typ {
let typ = self.interner.get_unresolved_type_data(*id);
Expand Down
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ pub enum QuotedType {
Quoted,
TopLevelItem,
Type,
TypedExpr,
StructDefinition,
TraitConstraint,
TraitDefinition,
Expand Down Expand Up @@ -741,6 +742,7 @@ impl std::fmt::Display for QuotedType {
QuotedType::Quoted => write!(f, "Quoted"),
QuotedType::TopLevelItem => write!(f, "TopLevelItem"),
QuotedType::Type => write!(f, "Type"),
QuotedType::TypedExpr => write!(f, "TypedExpr"),
QuotedType::StructDefinition => write!(f, "StructDefinition"),
QuotedType::TraitDefinition => write!(f, "TraitDefinition"),
QuotedType::TraitConstraint => write!(f, "TraitConstraint"),
Expand Down
3 changes: 3 additions & 0 deletions compiler/noirc_frontend/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,7 @@ pub enum Keyword {
TraitDefinition,
TraitImpl,
Type,
TypedExpr,
TypeType,
Unchecked,
Unconstrained,
Expand Down Expand Up @@ -1017,6 +1018,7 @@ impl fmt::Display for Keyword {
Keyword::TraitDefinition => write!(f, "TraitDefinition"),
Keyword::TraitImpl => write!(f, "TraitImpl"),
Keyword::Type => write!(f, "type"),
Keyword::TypedExpr => write!(f, "TypedExpr"),
Keyword::TypeType => write!(f, "Type"),
Keyword::Unchecked => write!(f, "unchecked"),
Keyword::Unconstrained => write!(f, "unconstrained"),
Expand Down Expand Up @@ -1075,6 +1077,7 @@ impl Keyword {
"TraitImpl" => Keyword::TraitImpl,
"type" => Keyword::Type,
"Type" => Keyword::TypeType,
"TypedExpr" => Keyword::TypedExpr,
"StructDefinition" => Keyword::StructDefinition,
"unchecked" => Keyword::Unchecked,
"unconstrained" => Keyword::Unconstrained,
Expand Down
7 changes: 7 additions & 0 deletions compiler/noirc_frontend/src/parser/parser/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub(super) fn comptime_type() -> impl NoirParser<UnresolvedType> {
type_of_quoted_types(),
top_level_item_type(),
quoted_type(),
typed_expr_type(),
))
}

Expand Down Expand Up @@ -159,6 +160,12 @@ fn quoted_type() -> impl NoirParser<UnresolvedType> {
.map_with_span(|_, span| UnresolvedTypeData::Quoted(QuotedType::Quoted).with_span(span))
}

/// This is the type of a typed/resolved expression.
fn typed_expr_type() -> impl NoirParser<UnresolvedType> {
keyword(Keyword::TypedExpr)
.map_with_span(|_, span| UnresolvedTypeData::Quoted(QuotedType::TypedExpr).with_span(span))
}

/// This is the type of an already resolved type.
/// The only way this can appear in the token input is if an already resolved `Type` object
/// was spliced into a macro's token stream via the `$` operator.
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>`
- `TypedExpr`: A type-checked expression.
- `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.
Expand Down
8 changes: 7 additions & 1 deletion docs/docs/noir/standard_library/meta/expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,10 @@ for expressions that are integers, doubling them, would return `(&[2], &[4, 6])`

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

Returns this expression as a `Quoted` value. It's the same as `quote { $self }`.
Returns this expression as a `Quoted` value. It's the same as `quote { $self }`.

### resolve

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

Resolves and type-checks this expression and returns the result as a `TypedExpr`. If any names used by this expression are not in scope or if there are any type errors, this will give compiler errors as if the expression was written directly into the current `comptime` function.
13 changes: 13 additions & 0 deletions docs/docs/noir/standard_library/meta/typed_expr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: TypedExpr
---

`std::meta::typed_expr` contains methods on the built-in `TypedExpr` type for resolved and type-checked expressions.

## Methods

### as_function_definition

#include_code as_function_definition noir_stdlib/src/meta/typed_expr.nr rust

If this expression refers to a function definitions, returns it. Otherwise returns `Option::none()`.
5 changes: 5 additions & 0 deletions noir_stdlib/src/meta/expr.nr
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ impl Expr {
// docs:end:quoted
quote { $self }
}

#[builtin(expr_resolve)]
// docs:start:resolve
fn resolve(self) -> TypedExpr {}
// docs:end:resolve
}

fn modify_array<Env>(expr: Expr, f: fn[Env](Expr) -> Option<Expr>) -> Option<Expr> {
Expand Down
1 change: 1 addition & 0 deletions noir_stdlib/src/meta/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod trait_constraint;
mod trait_def;
mod trait_impl;
mod typ;
mod typed_expr;
mod quoted;
mod unresolved_type;

Expand Down
8 changes: 8 additions & 0 deletions noir_stdlib/src/meta/typed_expr.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use crate::option::Option;

impl TypedExpr {
#[builtin(typed_expr_as_function_definition)]
// docs:start:as_function_definition
fn as_function_definition(self) -> Option<FunctionDefinition> {}
// docs:end:as_function_definition
}
11 changes: 11 additions & 0 deletions test_programs/noir_test_success/comptime_expr/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,17 @@ mod tests {
}
}

#[test]
fn test_resolve_to_function_definition() {
comptime
{
let expr = quote { times_two }.as_expr().unwrap();
let func = expr.resolve().as_function_definition().unwrap();
assert_eq(func.name(), quote { times_two });
assert_eq(func.parameters().len(), 1);
}
}

comptime fn get_unary_op(quoted: Quoted) -> UnaryOp {
let expr = quoted.as_expr().unwrap();
let (op, _) = expr.as_unary_op().unwrap();
Expand Down
2 changes: 2 additions & 0 deletions tooling/lsp/src/requests/completion/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pub(super) fn keyword_builtin_type(keyword: &Keyword) -> Option<&'static str> {
Keyword::TraitConstraint => Some("TraitConstraint"),
Keyword::TraitDefinition => Some("TraitDefinition"),
Keyword::TraitImpl => Some("TraitImpl"),
Keyword::TypedExpr => Some("TypedExpr"),
Keyword::TypeType => Some("Type"),
Keyword::UnresolvedType => Some("UnresolvedType"),

Expand Down Expand Up @@ -200,6 +201,7 @@ pub(super) fn keyword_builtin_function(keyword: &Keyword) -> Option<BuiltInFunct
| Keyword::TraitDefinition
| Keyword::TraitImpl
| Keyword::Type
| Keyword::TypedExpr
| Keyword::TypeType
| Keyword::Unchecked
| Keyword::Unconstrained
Expand Down