Skip to content

Commit 65da598

Browse files
authored
feat: add Expr::as_let (#5964)
# Description ## Problem Part of #5668 ## Summary Adds `Expr::as_let`, but also introduces a new `ExprValue` for patterns, their inlining code, etc. ## Additional Context I wonder if `Pattern` should be an `Expr` or something else, because it can't be converted to an expression like a statement or like an LValue 🤔 ## 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.
1 parent 5c74683 commit 65da598

File tree

16 files changed

+437
-71
lines changed

16 files changed

+437
-71
lines changed

aztec_macros/src/utils/parse_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ fn empty_pattern(pattern: &mut Pattern) {
401401
empty_pattern(pattern);
402402
}
403403
}
404+
Pattern::Interned(_, _) => (),
404405
}
405406
}
406407

compiler/noirc_frontend/src/ast/statement.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ use iter_extended::vecmap;
77
use noirc_errors::{Span, Spanned};
88

99
use super::{
10-
BlockExpression, Expression, ExpressionKind, GenericTypeArgs, IndexExpression, ItemVisibility,
11-
MemberAccessExpression, MethodCallExpression, UnresolvedType,
10+
BlockExpression, ConstructorExpression, Expression, ExpressionKind, GenericTypeArgs,
11+
IndexExpression, ItemVisibility, MemberAccessExpression, MethodCallExpression, UnresolvedType,
1212
};
1313
use crate::elaborator::types::SELF_TYPE_NAME;
1414
use crate::lexer::token::SpannedToken;
15-
use crate::macros_api::{SecondaryAttribute, UnresolvedTypeData};
16-
use crate::node_interner::{InternedExpressionKind, InternedStatementKind};
15+
use crate::macros_api::{NodeInterner, SecondaryAttribute, UnresolvedTypeData};
16+
use crate::node_interner::{InternedExpressionKind, InternedPattern, InternedStatementKind};
1717
use crate::parser::{ParserError, ParserErrorReason};
1818
use crate::token::Token;
1919

@@ -565,6 +565,7 @@ pub enum Pattern {
565565
Mutable(Box<Pattern>, Span, /*is_synthesized*/ bool),
566566
Tuple(Vec<Pattern>, Span),
567567
Struct(Path, Vec<(Ident, Pattern)>, Span),
568+
Interned(InternedPattern, Span),
568569
}
569570

570571
impl Pattern {
@@ -577,7 +578,8 @@ impl Pattern {
577578
Pattern::Identifier(ident) => ident.span(),
578579
Pattern::Mutable(_, span, _)
579580
| Pattern::Tuple(_, span)
580-
| Pattern::Struct(_, _, span) => *span,
581+
| Pattern::Struct(_, _, span)
582+
| Pattern::Interned(_, span) => *span,
581583
}
582584
}
583585
pub fn name_ident(&self) -> &Ident {
@@ -595,6 +597,39 @@ impl Pattern {
595597
other => panic!("Pattern::into_ident called on {other} pattern with no identifier"),
596598
}
597599
}
600+
601+
pub(crate) fn try_as_expression(&self, interner: &NodeInterner) -> Option<Expression> {
602+
match self {
603+
Pattern::Identifier(ident) => Some(Expression {
604+
kind: ExpressionKind::Variable(Path::from_ident(ident.clone())),
605+
span: ident.span(),
606+
}),
607+
Pattern::Mutable(_, _, _) => None,
608+
Pattern::Tuple(patterns, span) => {
609+
let mut expressions = Vec::new();
610+
for pattern in patterns {
611+
expressions.push(pattern.try_as_expression(interner)?);
612+
}
613+
Some(Expression { kind: ExpressionKind::Tuple(expressions), span: *span })
614+
}
615+
Pattern::Struct(path, patterns, span) => {
616+
let mut fields = Vec::new();
617+
for (field, pattern) in patterns {
618+
let expression = pattern.try_as_expression(interner)?;
619+
fields.push((field.clone(), expression));
620+
}
621+
Some(Expression {
622+
kind: ExpressionKind::Constructor(Box::new(ConstructorExpression {
623+
type_name: path.clone(),
624+
fields,
625+
struct_type: None,
626+
})),
627+
span: *span,
628+
})
629+
}
630+
Pattern::Interned(id, _) => interner.get_pattern(*id).try_as_expression(interner),
631+
}
632+
}
598633
}
599634

600635
impl Recoverable for Pattern {
@@ -905,6 +940,9 @@ impl Display for Pattern {
905940
let fields = vecmap(fields, |(name, pattern)| format!("{name}: {pattern}"));
906941
write!(f, "{} {{ {} }}", typename, fields.join(", "))
907942
}
943+
Pattern::Interned(_, _) => {
944+
write!(f, "?Interned")
945+
}
908946
}
909947
}
910948
}

compiler/noirc_frontend/src/ast/visitor.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use crate::{
1212
UseTreeKind,
1313
},
1414
node_interner::{
15-
ExprId, InternedExpressionKind, InternedStatementKind, InternedUnresolvedTypeData,
16-
QuotedTypeId,
15+
ExprId, InternedExpressionKind, InternedPattern, InternedStatementKind,
16+
InternedUnresolvedTypeData, QuotedTypeId,
1717
},
1818
parser::{Item, ItemKind, ParsedSubModule},
1919
token::{CustomAtrribute, SecondaryAttribute, Tokens},
@@ -440,6 +440,8 @@ pub trait Visitor {
440440
true
441441
}
442442

443+
fn visit_interned_pattern(&mut self, _: &InternedPattern, _: Span) {}
444+
443445
fn visit_secondary_attribute(
444446
&mut self,
445447
_: &SecondaryAttribute,
@@ -1321,6 +1323,9 @@ impl Pattern {
13211323
}
13221324
}
13231325
}
1326+
Pattern::Interned(id, span) => {
1327+
visitor.visit_interned_pattern(id, *span);
1328+
}
13241329
}
13251330
}
13261331
}

compiler/noirc_frontend/src/debug/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ fn pattern_vars(pattern: &ast::Pattern) -> Vec<(ast::Ident, bool)> {
675675
stack.extend(pids.iter().map(|(_, pattern)| (pattern, is_mut)));
676676
vars.extend(pids.iter().map(|(id, _)| (id.clone(), false)));
677677
}
678+
ast::Pattern::Interned(_, _) => (),
678679
}
679680
}
680681
vars
@@ -701,6 +702,7 @@ fn pattern_to_string(pattern: &ast::Pattern) -> String {
701702
.join(", "),
702703
)
703704
}
705+
ast::Pattern::Interned(_, _) => "?Interned".to_string(),
704706
}
705707
}
706708

compiler/noirc_frontend/src/elaborator/patterns.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,17 @@ impl<'context> Elaborator<'context> {
143143
mutable,
144144
new_definitions,
145145
),
146+
Pattern::Interned(id, _) => {
147+
let pattern = self.interner.get_pattern(id).clone();
148+
self.elaborate_pattern_mut(
149+
pattern,
150+
expected_type,
151+
definition,
152+
mutable,
153+
new_definitions,
154+
global_id,
155+
)
156+
}
146157
}
147158
}
148159

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,14 @@ pub enum InterpreterError {
220220
duplicate_location: Location,
221221
existing_location: Location,
222222
},
223+
CannotResolveExpression {
224+
location: Location,
225+
expression: String,
226+
},
227+
CannotSetFunctionBody {
228+
location: Location,
229+
expression: String,
230+
},
223231

224232
// These cases are not errors, they are just used to prevent us from running more code
225233
// until the loop can be resumed properly. These cases will never be displayed to users.
@@ -291,7 +299,9 @@ impl InterpreterError {
291299
| InterpreterError::InvalidAttribute { location, .. }
292300
| InterpreterError::GenericNameShouldBeAnIdent { location, .. }
293301
| InterpreterError::DuplicateGeneric { duplicate_location: location, .. }
294-
| InterpreterError::TypeAnnotationsNeededForMethodCall { location } => *location,
302+
| InterpreterError::TypeAnnotationsNeededForMethodCall { location }
303+
| InterpreterError::CannotResolveExpression { location, .. }
304+
| InterpreterError::CannotSetFunctionBody { location, .. } => *location,
295305

296306
InterpreterError::FailedToParseMacro { error, file, .. } => {
297307
Location::new(error.span(), *file)
@@ -626,6 +636,14 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic {
626636
);
627637
error
628638
}
639+
InterpreterError::CannotResolveExpression { location, expression } => {
640+
let msg = format!("Cannot resolve expression `{expression}`");
641+
CustomDiagnostic::simple_error(msg, String::new(), location.span)
642+
}
643+
InterpreterError::CannotSetFunctionBody { location, expression } => {
644+
let msg = format!("`{expression}` is not a valid function body");
645+
CustomDiagnostic::simple_error(msg, String::new(), location.span)
646+
}
629647
}
630648
}
631649
}

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

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use rustc_hash::FxHashMap as HashMap;
2222
use crate::{
2323
ast::{
2424
ArrayLiteral, BlockExpression, ConstrainKind, Expression, ExpressionKind, FunctionKind,
25-
FunctionReturnType, IntegerBitSize, LValue, Literal, Statement, StatementKind, UnaryOp,
26-
UnresolvedType, UnresolvedTypeData, Visibility,
25+
FunctionReturnType, IntegerBitSize, LValue, Literal, Pattern, Statement, StatementKind,
26+
UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility,
2727
},
2828
hir::def_collector::dc_crate::CollectedItems,
2929
hir::{
@@ -78,6 +78,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
7878
"expr_as_if" => expr_as_if(interner, arguments, return_type, location),
7979
"expr_as_index" => expr_as_index(interner, arguments, return_type, location),
8080
"expr_as_integer" => expr_as_integer(interner, arguments, return_type, location),
81+
"expr_as_let" => expr_as_let(interner, arguments, return_type, location),
8182
"expr_as_member_access" => {
8283
expr_as_member_access(interner, arguments, return_type, location)
8384
}
@@ -1500,6 +1501,41 @@ fn expr_as_integer(
15001501
})
15011502
}
15021503

1504+
// fn as_let(self) -> Option<(Expr, Option<UnresolvedType>, Expr)>
1505+
fn expr_as_let(
1506+
interner: &NodeInterner,
1507+
arguments: Vec<(Value, Location)>,
1508+
return_type: Type,
1509+
location: Location,
1510+
) -> IResult<Value> {
1511+
expr_as(interner, arguments, return_type.clone(), location, |expr| match expr {
1512+
ExprValue::Statement(StatementKind::Let(let_statement)) => {
1513+
let option_type = extract_option_generic_type(return_type);
1514+
let Type::Tuple(mut tuple_types) = option_type else {
1515+
panic!("Expected the return type option generic arg to be a tuple");
1516+
};
1517+
assert_eq!(tuple_types.len(), 3);
1518+
tuple_types.pop().unwrap();
1519+
let option_type = tuple_types.pop().unwrap();
1520+
1521+
let typ = if let_statement.r#type.typ == UnresolvedTypeData::Unspecified {
1522+
None
1523+
} else {
1524+
Some(Value::UnresolvedType(let_statement.r#type.typ))
1525+
};
1526+
1527+
let typ = option(option_type, typ).ok()?;
1528+
1529+
Some(Value::Tuple(vec![
1530+
Value::pattern(let_statement.pattern),
1531+
typ,
1532+
Value::expression(let_statement.expression.kind),
1533+
]))
1534+
}
1535+
_ => None,
1536+
})
1537+
}
1538+
15031539
// fn as_member_access(self) -> Option<(Expr, Quoted)>
15041540
fn expr_as_member_access(
15051541
interner: &NodeInterner,
@@ -1777,27 +1813,33 @@ fn expr_resolve(
17771813
interpreter.current_function
17781814
};
17791815

1780-
let value =
1781-
interpreter.elaborate_in_function(function_to_resolve_in, |elaborator| match expr_value {
1782-
ExprValue::Expression(expression_kind) => {
1783-
let expr = Expression { kind: expression_kind, span: self_argument_location.span };
1784-
let (expr_id, _) = elaborator.elaborate_expression(expr);
1785-
Value::TypedExpr(TypedExpr::ExprId(expr_id))
1786-
}
1787-
ExprValue::Statement(statement_kind) => {
1788-
let statement =
1789-
Statement { kind: statement_kind, span: self_argument_location.span };
1790-
let (stmt_id, _) = elaborator.elaborate_statement(statement);
1791-
Value::TypedExpr(TypedExpr::StmtId(stmt_id))
1792-
}
1793-
ExprValue::LValue(lvalue) => {
1794-
let expr = lvalue.as_expression();
1795-
let (expr_id, _) = elaborator.elaborate_expression(expr);
1796-
Value::TypedExpr(TypedExpr::ExprId(expr_id))
1816+
interpreter.elaborate_in_function(function_to_resolve_in, |elaborator| match expr_value {
1817+
ExprValue::Expression(expression_kind) => {
1818+
let expr = Expression { kind: expression_kind, span: self_argument_location.span };
1819+
let (expr_id, _) = elaborator.elaborate_expression(expr);
1820+
Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id)))
1821+
}
1822+
ExprValue::Statement(statement_kind) => {
1823+
let statement = Statement { kind: statement_kind, span: self_argument_location.span };
1824+
let (stmt_id, _) = elaborator.elaborate_statement(statement);
1825+
Ok(Value::TypedExpr(TypedExpr::StmtId(stmt_id)))
1826+
}
1827+
ExprValue::LValue(lvalue) => {
1828+
let expr = lvalue.as_expression();
1829+
let (expr_id, _) = elaborator.elaborate_expression(expr);
1830+
Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id)))
1831+
}
1832+
ExprValue::Pattern(pattern) => {
1833+
if let Some(expression) = pattern.try_as_expression(elaborator.interner) {
1834+
let (expr_id, _) = elaborator.elaborate_expression(expression);
1835+
Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id)))
1836+
} else {
1837+
let expression = Value::pattern(pattern).display(elaborator.interner).to_string();
1838+
let location = self_argument_location;
1839+
Err(InterpreterError::CannotResolveExpression { location, expression })
17971840
}
1798-
});
1799-
1800-
Ok(value)
1841+
}
1842+
})
18011843
}
18021844

18031845
fn unwrap_expr_value(interner: &NodeInterner, mut expr_value: ExprValue) -> ExprValue {
@@ -1819,6 +1861,9 @@ fn unwrap_expr_value(interner: &NodeInterner, mut expr_value: ExprValue) -> Expr
18191861
ExprValue::LValue(LValue::Interned(id, span)) => {
18201862
expr_value = ExprValue::LValue(interner.get_lvalue(id, span).clone());
18211863
}
1864+
ExprValue::Pattern(Pattern::Interned(id, _)) => {
1865+
expr_value = ExprValue::Pattern(interner.get_pattern(id).clone());
1866+
}
18221867
_ => break,
18231868
}
18241869
}
@@ -2031,6 +2076,16 @@ fn function_def_set_body(
20312076
}),
20322077
ExprValue::Statement(statement_kind) => statement_kind,
20332078
ExprValue::LValue(lvalue) => StatementKind::Expression(lvalue.as_expression()),
2079+
ExprValue::Pattern(pattern) => {
2080+
if let Some(expression) = pattern.try_as_expression(interpreter.elaborator.interner) {
2081+
StatementKind::Expression(expression)
2082+
} else {
2083+
let expression =
2084+
Value::pattern(pattern).display(interpreter.elaborator.interner).to_string();
2085+
let location = body_location;
2086+
return Err(InterpreterError::CannotSetFunctionBody { location, expression });
2087+
}
2088+
}
20342089
};
20352090

20362091
let statement = Statement { kind: statement_kind, span: body_location.span };

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use noirc_errors::Location;
55

66
use crate::{
77
ast::{
8-
BlockExpression, ExpressionKind, IntegerBitSize, LValue, Signedness, StatementKind,
9-
UnresolvedTypeData,
8+
BlockExpression, ExpressionKind, IntegerBitSize, LValue, Pattern, Signedness,
9+
StatementKind, UnresolvedTypeData,
1010
},
1111
elaborator::Elaborator,
1212
hir::{
@@ -191,6 +191,9 @@ pub(crate) fn get_expr(
191191
ExprValue::LValue(LValue::Interned(id, _)) => {
192192
Ok(ExprValue::LValue(interner.get_lvalue(id, location.span).clone()))
193193
}
194+
ExprValue::Pattern(Pattern::Interned(id, _)) => {
195+
Ok(ExprValue::Pattern(interner.get_pattern(id).clone()))
196+
}
194197
_ => Ok(expr),
195198
},
196199
value => type_mismatch(value, Type::Quoted(QuotedType::Expr), location),

0 commit comments

Comments
 (0)