Skip to content

Commit bceee55

Browse files
asteritejfecher
andauthored
feat: add Expr::resolve and TypedExpr::as_function_definition (#5859)
# Description ## Problem Part of #5668 ## Summary ## Additional Context ## Documentation Check one: - [ ] No documentation needed. - [x] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: jfecher <[email protected]>
1 parent 663e00c commit bceee55

15 files changed

Lines changed: 156 additions & 14 deletions

File tree

compiler/noirc_frontend/src/elaborator/statements.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'context> Elaborator<'context> {
4848
}
4949
}
5050

51-
pub(super) fn elaborate_statement(&mut self, statement: Statement) -> (StmtId, Type) {
51+
pub(crate) fn elaborate_statement(&mut self, statement: Statement) -> (StmtId, Type) {
5252
let span = statement.span;
5353
let (hir_statement, typ) = self.elaborate_statement_value(statement);
5454
let id = self.interner.push_stmt(hir_statement);

compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use builtin_helpers::{
88
block_expression_to_value, check_argument_count, check_function_not_yet_resolved,
99
check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_field,
1010
get_function_def, get_module, get_quoted, get_slice, get_struct, get_trait_constraint,
11-
get_trait_def, get_trait_impl, get_tuple, get_type, get_u32, get_unresolved_type,
12-
hir_pattern_to_tokens, mutate_func_meta_type, parse, replace_func_meta_parameters,
13-
replace_func_meta_return_type,
11+
get_trait_def, get_trait_impl, get_tuple, get_type, get_typed_expr, get_u32,
12+
get_unresolved_type, hir_pattern_to_tokens, mutate_func_meta_type, parse,
13+
replace_func_meta_parameters, replace_func_meta_return_type,
1414
};
1515
use chumsky::{prelude::choice, Parser};
1616
use im::Vector;
@@ -25,7 +25,11 @@ use crate::{
2525
FunctionReturnType, IntegerBitSize, LValue, Literal, Statement, StatementKind, UnaryOp,
2626
UnresolvedType, UnresolvedTypeData, Visibility,
2727
},
28-
hir::comptime::{errors::IResult, value::ExprValue, InterpreterError, Value},
28+
hir::comptime::{
29+
errors::IResult,
30+
value::{ExprValue, TypedExpr},
31+
InterpreterError, Value,
32+
},
2933
hir_def::function::FunctionBody,
3034
macros_api::{HirExpression, HirLiteral, ModuleDefId, NodeInterner, Signedness},
3135
node_interner::{DefinitionKind, TraitImplKind},
@@ -87,6 +91,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
8791
"expr_has_semicolon" => expr_has_semicolon(interner, arguments, location),
8892
"expr_is_break" => expr_is_break(interner, arguments, location),
8993
"expr_is_continue" => expr_is_continue(interner, arguments, location),
94+
"expr_resolve" => expr_resolve(self, arguments, location),
9095
"is_unconstrained" => Ok(Value::Bool(true)),
9196
"function_def_body" => function_def_body(interner, arguments, location),
9297
"function_def_name" => function_def_name(interner, arguments, location),
@@ -145,6 +150,9 @@ impl<'local, 'context> Interpreter<'local, 'context> {
145150
"type_is_bool" => type_is_bool(arguments, location),
146151
"type_is_field" => type_is_field(arguments, location),
147152
"type_of" => type_of(arguments, location),
153+
"typed_expr_as_function_definition" => {
154+
typed_expr_as_function_definition(interner, arguments, return_type, location)
155+
}
148156
"unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location),
149157
"zeroed" => zeroed(return_type),
150158
_ => {
@@ -763,6 +771,23 @@ fn trait_impl_trait_generic_args(
763771
Ok(Value::Slice(trait_generics, slice_type))
764772
}
765773

774+
fn typed_expr_as_function_definition(
775+
interner: &NodeInterner,
776+
arguments: Vec<(Value, Location)>,
777+
return_type: Type,
778+
location: Location,
779+
) -> IResult<Value> {
780+
let self_argument = check_one_argument(arguments, location)?;
781+
let typed_expr = get_typed_expr(self_argument)?;
782+
let option_value = if let TypedExpr::ExprId(expr_id) = typed_expr {
783+
let func_id = interner.lookup_function_from_expr(&expr_id);
784+
func_id.map(Value::FunctionDefinition)
785+
} else {
786+
None
787+
};
788+
option(return_type, option_value)
789+
}
790+
766791
// fn is_field(self) -> bool
767792
fn unresolved_type_is_field(
768793
interner: &NodeInterner,
@@ -1380,7 +1405,48 @@ where
13801405
F: FnOnce(ExprValue) -> Option<Value>,
13811406
{
13821407
let self_argument = check_one_argument(arguments, location)?;
1383-
let mut expr_value = get_expr(interner, self_argument)?;
1408+
let expr_value = get_expr(interner, self_argument)?;
1409+
let expr_value = unwrap_expr_value(interner, expr_value);
1410+
1411+
let option_value = f(expr_value);
1412+
option(return_type, option_value)
1413+
}
1414+
1415+
// fn resolve(self) -> TypedExpr
1416+
fn expr_resolve(
1417+
interpreter: &mut Interpreter,
1418+
arguments: Vec<(Value, Location)>,
1419+
location: Location,
1420+
) -> IResult<Value> {
1421+
let self_argument = check_one_argument(arguments, location)?;
1422+
let self_argument_location = self_argument.1;
1423+
let expr_value = get_expr(interpreter.elaborator.interner, self_argument)?;
1424+
let expr_value = unwrap_expr_value(interpreter.elaborator.interner, expr_value);
1425+
1426+
let value =
1427+
interpreter.elaborate_item(interpreter.current_function, |elaborator| match expr_value {
1428+
ExprValue::Expression(expression_kind) => {
1429+
let expr = Expression { kind: expression_kind, span: self_argument_location.span };
1430+
let (expr_id, _) = elaborator.elaborate_expression(expr);
1431+
Value::TypedExpr(TypedExpr::ExprId(expr_id))
1432+
}
1433+
ExprValue::Statement(statement_kind) => {
1434+
let statement =
1435+
Statement { kind: statement_kind, span: self_argument_location.span };
1436+
let (stmt_id, _) = elaborator.elaborate_statement(statement);
1437+
Value::TypedExpr(TypedExpr::StmtId(stmt_id))
1438+
}
1439+
ExprValue::LValue(lvalue) => {
1440+
let expr = lvalue.as_expression();
1441+
let (expr_id, _) = elaborator.elaborate_expression(expr);
1442+
Value::TypedExpr(TypedExpr::ExprId(expr_id))
1443+
}
1444+
});
1445+
1446+
Ok(value)
1447+
}
1448+
1449+
fn unwrap_expr_value(interner: &NodeInterner, mut expr_value: ExprValue) -> ExprValue {
13841450
loop {
13851451
match expr_value {
13861452
ExprValue::Expression(ExpressionKind::Parenthesized(expression)) => {
@@ -1402,9 +1468,7 @@ where
14021468
_ => break,
14031469
}
14041470
}
1405-
1406-
let option_value = f(expr_value);
1407-
option(return_type, option_value)
1471+
expr_value
14081472
}
14091473

14101474
// fn body(self) -> Expr

compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
hir::{
1212
comptime::{
1313
errors::IResult,
14-
value::{add_token_spans, ExprValue},
14+
value::{add_token_spans, ExprValue, TypedExpr},
1515
Interpreter, InterpreterError, Value,
1616
},
1717
def_map::ModuleId,
@@ -227,6 +227,13 @@ pub(crate) fn get_type((value, location): (Value, Location)) -> IResult<Type> {
227227
}
228228
}
229229

230+
pub(crate) fn get_typed_expr((value, location): (Value, Location)) -> IResult<TypedExpr> {
231+
match value {
232+
Value::TypedExpr(typed_expr) => Ok(typed_expr),
233+
value => type_mismatch(value, Type::Quoted(QuotedType::TypedExpr), location),
234+
}
235+
}
236+
230237
pub(crate) fn get_quoted((value, location): (Value, Location)) -> IResult<Rc<Vec<Token>>> {
231238
match value {
232239
Value::Quoted(tokens) => Ok(tokens),

compiler/noirc_frontend/src/hir/comptime/value.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::{
2424
Expression, ExpressionKind, HirExpression, HirLiteral, Literal, NodeInterner, Path,
2525
StructId,
2626
},
27-
node_interner::{ExprId, FuncId, TraitId, TraitImplId},
27+
node_interner::{ExprId, FuncId, StmtId, TraitId, TraitImplId},
2828
parser::{self, NoirParser, TopLevelStatement},
2929
token::{SpannedToken, Token, Tokens},
3030
QuotedType, Shared, Type, TypeBindings,
@@ -69,6 +69,7 @@ pub enum Value {
6969
Type(Type),
7070
Zeroed(Type),
7171
Expr(ExprValue),
72+
TypedExpr(TypedExpr),
7273
UnresolvedType(UnresolvedTypeData),
7374
}
7475

@@ -79,6 +80,12 @@ pub enum ExprValue {
7980
LValue(LValue),
8081
}
8182

83+
#[derive(Debug, Clone, PartialEq, Eq, Display)]
84+
pub enum TypedExpr {
85+
ExprId(ExprId),
86+
StmtId(StmtId),
87+
}
88+
8289
impl Value {
8390
pub(crate) fn expression(expr: ExpressionKind) -> Self {
8491
Value::Expr(ExprValue::Expression(expr))
@@ -137,6 +144,7 @@ impl Value {
137144
Value::Type(_) => Type::Quoted(QuotedType::Type),
138145
Value::Zeroed(typ) => return Cow::Borrowed(typ),
139146
Value::Expr(_) => Type::Quoted(QuotedType::Expr),
147+
Value::TypedExpr(_) => Type::Quoted(QuotedType::TypedExpr),
140148
Value::UnresolvedType(_) => Type::Quoted(QuotedType::UnresolvedType),
141149
})
142150
}
@@ -264,7 +272,8 @@ impl Value {
264272
statements: vec![Statement { kind: statement, span: location.span }],
265273
})
266274
}
267-
Value::Expr(ExprValue::LValue(_))
275+
Value::Expr(ExprValue::LValue(lvalue)) => lvalue.as_expression().kind,
276+
Value::TypedExpr(..)
268277
| Value::Pointer(..)
269278
| Value::StructDefinition(_)
270279
| Value::TraitConstraint(..)
@@ -389,7 +398,9 @@ impl Value {
389398
HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements)))
390399
}
391400
Value::Quoted(tokens) => HirExpression::Unquote(add_token_spans(tokens, location.span)),
392-
Value::Expr(..)
401+
Value::TypedExpr(TypedExpr::ExprId(expr_id)) => interner.expression(&expr_id),
402+
Value::TypedExpr(TypedExpr::StmtId(..))
403+
| Value::Expr(..)
393404
| Value::Pointer(..)
394405
| Value::StructDefinition(_)
395406
| Value::TraitConstraint(..)
@@ -621,6 +632,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> {
621632
Value::Expr(ExprValue::LValue(lvalue)) => {
622633
write!(f, "{}", remove_interned_in_lvalue(self.interner, lvalue.clone()))
623634
}
635+
Value::TypedExpr(_) => write!(f, "(typed expr)"),
624636
Value::UnresolvedType(typ) => {
625637
if let UnresolvedTypeData::Interned(id) = typ {
626638
let typ = self.interner.get_unresolved_type_data(*id);

compiler/noirc_frontend/src/hir_def/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub enum QuotedType {
153153
Quoted,
154154
TopLevelItem,
155155
Type,
156+
TypedExpr,
156157
StructDefinition,
157158
TraitConstraint,
158159
TraitDefinition,
@@ -741,6 +742,7 @@ impl std::fmt::Display for QuotedType {
741742
QuotedType::Quoted => write!(f, "Quoted"),
742743
QuotedType::TopLevelItem => write!(f, "TopLevelItem"),
743744
QuotedType::Type => write!(f, "Type"),
745+
QuotedType::TypedExpr => write!(f, "TypedExpr"),
744746
QuotedType::StructDefinition => write!(f, "StructDefinition"),
745747
QuotedType::TraitDefinition => write!(f, "TraitDefinition"),
746748
QuotedType::TraitConstraint => write!(f, "TraitConstraint"),

compiler/noirc_frontend/src/lexer/token.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,7 @@ pub enum Keyword {
962962
TraitDefinition,
963963
TraitImpl,
964964
Type,
965+
TypedExpr,
965966
TypeType,
966967
Unchecked,
967968
Unconstrained,
@@ -1017,6 +1018,7 @@ impl fmt::Display for Keyword {
10171018
Keyword::TraitDefinition => write!(f, "TraitDefinition"),
10181019
Keyword::TraitImpl => write!(f, "TraitImpl"),
10191020
Keyword::Type => write!(f, "type"),
1021+
Keyword::TypedExpr => write!(f, "TypedExpr"),
10201022
Keyword::TypeType => write!(f, "Type"),
10211023
Keyword::Unchecked => write!(f, "unchecked"),
10221024
Keyword::Unconstrained => write!(f, "unconstrained"),
@@ -1075,6 +1077,7 @@ impl Keyword {
10751077
"TraitImpl" => Keyword::TraitImpl,
10761078
"type" => Keyword::Type,
10771079
"Type" => Keyword::TypeType,
1080+
"TypedExpr" => Keyword::TypedExpr,
10781081
"StructDefinition" => Keyword::StructDefinition,
10791082
"unchecked" => Keyword::Unchecked,
10801083
"unconstrained" => Keyword::Unconstrained,

compiler/noirc_frontend/src/parser/parser/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub(super) fn comptime_type() -> impl NoirParser<UnresolvedType> {
8888
type_of_quoted_types(),
8989
top_level_item_type(),
9090
quoted_type(),
91+
typed_expr_type(),
9192
))
9293
}
9394

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

163+
/// This is the type of a typed/resolved expression.
164+
fn typed_expr_type() -> impl NoirParser<UnresolvedType> {
165+
keyword(Keyword::TypedExpr)
166+
.map_with_span(|_, span| UnresolvedTypeData::Quoted(QuotedType::TypedExpr).with_span(span))
167+
}
168+
162169
/// This is the type of an already resolved type.
163170
/// The only way this can appear in the token input is if an already resolved `Type` object
164171
/// was spliced into a macro's token stream via the `$` operator.

docs/docs/noir/concepts/comptime.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ The following is an incomplete list of some `comptime` types along with some use
232232
- `fn fields(self) -> [(Quoted, Type)]`
233233
- Return the name and type of each field
234234
- `TraitConstraint`: A trait constraint such as `From<Field>`
235+
- `TypedExpr`: A type-checked expression.
235236
- `UnresolvedType`: A syntactic notation that refers to a Noir type that hasn't been resolved yet
236237

237238
There are many more functions available by exploring the `std::meta` module and its submodules.

docs/docs/noir/standard_library/meta/expr.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,10 @@ for expressions that are integers, doubling them, would return `(&[2], &[4, 6])`
184184

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

187-
Returns this expression as a `Quoted` value. It's the same as `quote { $self }`.
187+
Returns this expression as a `Quoted` value. It's the same as `quote { $self }`.
188+
189+
### resolve
190+
191+
#include_code resolve noir_stdlib/src/meta/expr.nr rust
192+
193+
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.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
title: TypedExpr
3+
---
4+
5+
`std::meta::typed_expr` contains methods on the built-in `TypedExpr` type for resolved and type-checked expressions.
6+
7+
## Methods
8+
9+
### as_function_definition
10+
11+
#include_code as_function_definition noir_stdlib/src/meta/typed_expr.nr rust
12+
13+
If this expression refers to a function definitions, returns it. Otherwise returns `Option::none()`.

0 commit comments

Comments
 (0)