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

chore(experimental): Improve variable not defined error message in comptime interpreter #4889

Merged
merged 34 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
237418f
Add Hir -> Ast conversion
jfecher Apr 10, 2024
88fbae4
Move file
jfecher Apr 11, 2024
d4512ac
Add Hir -> Ast pass
jfecher Apr 11, 2024
dd05c5f
Merge branch 'master' into jf/hir-to-ast
jfecher Apr 12, 2024
064a074
Add weird attributes field even though it was compiling locally witho…
jfecher Apr 12, 2024
99b7839
Start work on interpreter
jfecher Apr 12, 2024
2232793
Evaluate if exprs
jfecher Apr 12, 2024
1c649e5
Update interpreter
jfecher Apr 15, 2024
b5bdb9c
Start evaluating statements
jfecher Apr 15, 2024
65a0da9
Fix compiler errors
jfecher Apr 15, 2024
9d5517b
Implement loops
jfecher Apr 15, 2024
9a31f68
Finish each node; still needs cleanup & testing
jfecher Apr 15, 2024
4247e89
Fix mutation after scopes were added
jfecher Apr 16, 2024
7121ec7
Implement function scopes
jfecher Apr 16, 2024
65fc2e1
clippy
jfecher Apr 16, 2024
20ac4e9
Merge branch 'master' into jf/interpreter
jfecher Apr 16, 2024
2bf6ea7
Add comptime expression & statement
jfecher Apr 17, 2024
a901d8f
Add comptime hir node
jfecher Apr 17, 2024
3443545
Handle comptime node in comptime module
jfecher Apr 18, 2024
55c28b4
Add case to tooling
jfecher Apr 18, 2024
3d08598
Merge branch 'master' into jf/comptime
jfecher Apr 18, 2024
9ebf902
Fix merge
jfecher Apr 18, 2024
4e4f9fd
Add missed case
jfecher Apr 18, 2024
824c4b2
Remove comptime from parse tests
jfecher Apr 18, 2024
63fdb4a
Add scanning pass
jfecher Apr 18, 2024
e376121
Refactor name resolution a bit
jfecher Apr 19, 2024
65f6513
Add into_expression
jfecher Apr 22, 2024
11a6acd
Finish fleshing out into_expression
jfecher Apr 22, 2024
b39f42b
Fix many many merge conflicts
jfecher Apr 22, 2024
a4e596e
fmt
jfecher Apr 22, 2024
7e75b64
Code review
jfecher Apr 23, 2024
522867b
Improve error slightly
jfecher Apr 23, 2024
95b6a19
Merge branch 'master' into jf/comptime-checked
jfecher Apr 23, 2024
47ef177
Finish missed CompTime -> Comptime cases
jfecher Apr 23, 2024
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
8 changes: 4 additions & 4 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub enum StatementKind {
Break,
Continue,
/// This statement should be executed at compile-time
CompTime(Box<StatementKind>),
Comptime(Box<StatementKind>),
// This is an expression with a trailing semi-colon
Semi(Expression),
// This statement is the result of a recovered parse error.
Expand Down Expand Up @@ -87,10 +87,10 @@ impl StatementKind {
}
self
}
StatementKind::CompTime(mut statement) => {
StatementKind::Comptime(mut statement) => {
*statement =
statement.add_semicolon(semi, span, last_statement_in_block, emit_error);
StatementKind::CompTime(statement)
StatementKind::Comptime(statement)
}
// A semicolon on a for loop is optional and does nothing
StatementKind::For(_) => self,
Expand Down Expand Up @@ -685,7 +685,7 @@ impl Display for StatementKind {
StatementKind::For(for_loop) => for_loop.fmt(f),
StatementKind::Break => write!(f, "break"),
StatementKind::Continue => write!(f, "continue"),
StatementKind::CompTime(statement) => write!(f, "comptime {statement}"),
StatementKind::Comptime(statement) => write!(f, "comptime {statement}"),
StatementKind::Semi(semi) => write!(f, "{semi};"),
StatementKind::Error => write!(f, "Error"),
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{node_interner::DefinitionId, Type};
use crate::Type;
use acvm::FieldElement;
use noirc_errors::Location;

Expand All @@ -9,7 +9,7 @@ use super::value::Value;
pub enum InterpreterError {
ArgumentCountMismatch { expected: usize, actual: usize, call_location: Location },
TypeMismatch { expected: Type, value: Value, location: Location },
NoValueForId { id: DefinitionId, location: Location },
NonComptimeVarReferenced { name: String, location: Location },
IntegerOutOfRangeForType { value: FieldElement, typ: Type, location: Location },
ErrorNodeEncountered { location: Location },
NonFunctionCalled { value: Value, location: Location },
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ impl StmtId {
HirStatement::Expression(expr) => StatementKind::Expression(expr.to_ast(interner)),
HirStatement::Semi(expr) => StatementKind::Semi(expr.to_ast(interner)),
HirStatement::Error => StatementKind::Error,
HirStatement::CompTime(statement) => {
StatementKind::CompTime(Box::new(statement.to_ast(interner).kind))
HirStatement::Comptime(statement) => {
StatementKind::Comptime(Box::new(statement.to_ast(interner).kind))
}
};

Expand Down
28 changes: 11 additions & 17 deletions compiler/noirc_frontend/src/hir/comptime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,7 @@ impl<'a> Interpreter<'a> {
location: Location,
) -> IResult<()> {
self.type_check(typ, &argument, location)?;
for scope in self.scopes.iter_mut().rev() {
if let Entry::Occupied(mut entry) = scope.entry(id) {
entry.insert(argument);
return Ok(());
}
}
Err(InterpreterError::NoValueForId { id, location })
self.mutate(id, argument, location)
}

/// Mutate an existing variable, potentially from a prior scope
Expand All @@ -263,17 +257,12 @@ impl<'a> Interpreter<'a> {
return Ok(());
}
}
Err(InterpreterError::NoValueForId { id, location })
let name = self.interner.definition(id).name.clone();
Err(InterpreterError::NonComptimeVarReferenced { name, location })
}

fn lookup(&self, ident: &HirIdent) -> IResult<Value> {
for scope in self.scopes.iter().rev() {
if let Some(value) = scope.get(&ident.id) {
return Ok(value.clone());
}
}

Err(InterpreterError::NoValueForId { id: ident.id, location: ident.location })
self.lookup_id(ident.id, ident.location)
}

fn lookup_id(&self, id: DefinitionId, location: Location) -> IResult<Value> {
Expand All @@ -283,7 +272,12 @@ impl<'a> Interpreter<'a> {
}
}

Err(InterpreterError::NoValueForId { id, location })
// Justification for `NonComptimeVarReferenced`:
// If we have an id to lookup at all that means name resolution successfully
// found another variable in scope for this name. If the name is in scope
// but unknown by the interpreter it must be because it was not a comptime variable.
let name = self.interner.definition(id).name.clone();
Err(InterpreterError::NonComptimeVarReferenced { name, location })
}

fn type_check(&self, typ: &Type, value: &Value, location: Location) -> IResult<()> {
Expand Down Expand Up @@ -1023,7 +1017,7 @@ impl<'a> Interpreter<'a> {
HirStatement::Break => self.evaluate_break(statement),
HirStatement::Continue => self.evaluate_continue(statement),
HirStatement::Expression(expression) => self.evaluate(expression),
HirStatement::CompTime(statement) => self.evaluate_comptime(statement),
HirStatement::Comptime(statement) => self.evaluate_comptime(statement),
HirStatement::Semi(expression) => {
self.evaluate(expression)?;
Ok(Value::Unit)
Expand Down
10 changes: 5 additions & 5 deletions compiler/noirc_frontend/src/hir/comptime/scan.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//! This module is for the scanning of the Hir by the interpreter.
//! In this initial step, the Hir is scanned for `CompTime` nodes
//! In this initial step, the Hir is scanned for `Comptime` nodes
//! without actually executing anything until such a node is found.
//! Once such a node is found, the interpreter will call the relevant
//! evaluate method on that node type, insert the result into the Ast,
//! and continue scanning the rest of the program.
//!
//! Since it mostly just needs to recur on the Hir looking for CompTime
//! Since it mostly just needs to recur on the Hir looking for Comptime
//! nodes, this pass is fairly simple. The only thing it really needs to
//! ensure to do is to push and pop scopes on the interpreter as needed
//! so that any variables defined within e.g. an `if` statement containing
//! a `CompTime` block aren't accessible outside of the `if`.
//! a `Comptime` block aren't accessible outside of the `if`.
use crate::{
hir_def::{
expr::{
Expand All @@ -30,7 +30,7 @@ use super::{

#[allow(dead_code)]
impl<'interner> Interpreter<'interner> {
/// Scan through a function, evaluating any CompTime nodes found.
/// Scan through a function, evaluating any Comptime nodes found.
/// These nodes will be modified in place, replaced with the
/// result of their evaluation.
pub fn scan_function(&mut self, function: FuncId) -> IResult<()> {
Expand Down Expand Up @@ -185,7 +185,7 @@ impl<'interner> Interpreter<'interner> {
HirStatement::Expression(expression) => self.scan_expression(expression),
HirStatement::Semi(semi) => self.scan_expression(semi),
HirStatement::Error => Ok(()),
HirStatement::CompTime(comptime) => {
HirStatement::Comptime(comptime) => {
let location = self.interner.statement_location(comptime);
let new_expr =
self.evaluate_comptime(comptime)?.into_expression(self.interner, location)?;
Expand Down
1 change: 0 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use rustc_hash::FxHashMap as HashMap;

use super::errors::{IResult, InterpreterError};

#[allow(unused)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
Unit,
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1272,9 +1272,9 @@ impl<'a> Resolver<'a> {
HirStatement::Continue
}
StatementKind::Error => HirStatement::Error,
StatementKind::CompTime(statement) => {
StatementKind::Comptime(statement) => {
let statement = self.resolve_stmt(*statement, span);
HirStatement::CompTime(self.interner.push_stmt(statement))
HirStatement::Comptime(self.interner.push_stmt(statement))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir/type_check/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl<'interner> TypeChecker<'interner> {
HirStatement::Constrain(constrain_stmt) => self.check_constrain_stmt(constrain_stmt),
HirStatement::Assign(assign_stmt) => self.check_assign_stmt(assign_stmt, stmt_id),
HirStatement::For(for_loop) => self.check_for_loop(for_loop),
HirStatement::CompTime(statement) => return self.check_statement(&statement),
HirStatement::Comptime(statement) => return self.check_statement(&statement),
HirStatement::Break | HirStatement::Continue | HirStatement::Error => (),
}
Type::Unit
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir_def/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub enum HirStatement {
Continue,
Expression(ExprId),
Semi(ExprId),
CompTime(StmtId),
Comptime(StmtId),
Error,
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/noirc_frontend/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ pub enum Keyword {
Break,
CallData,
Char,
CompTime,
Comptime,
Constrain,
Continue,
Contract,
Expand Down Expand Up @@ -856,7 +856,7 @@ impl fmt::Display for Keyword {
Keyword::Break => write!(f, "break"),
Keyword::Char => write!(f, "char"),
Keyword::CallData => write!(f, "call_data"),
Keyword::CompTime => write!(f, "comptime"),
Keyword::Comptime => write!(f, "comptime"),
Keyword::Constrain => write!(f, "constrain"),
Keyword::Continue => write!(f, "continue"),
Keyword::Contract => write!(f, "contract"),
Expand Down Expand Up @@ -904,7 +904,7 @@ impl Keyword {
"break" => Keyword::Break,
"call_data" => Keyword::CallData,
"char" => Keyword::Char,
"comptime" => Keyword::CompTime,
"comptime" => Keyword::Comptime,
"constrain" => Keyword::Constrain,
"continue" => Keyword::Continue,
"contract" => Keyword::Contract,
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ impl<'interner> Monomorphizer<'interner> {
HirStatement::Error => unreachable!(),

// All `comptime` statements & expressions should be removed before runtime.
HirStatement::CompTime(_) => unreachable!("comptime statement in runtime code"),
HirStatement::Comptime(_) => unreachable!("comptime statement in runtime code"),
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/noir_parser.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ extern {
"break" => BorrowedToken::Keyword(noir_token::Keyword::Break),
"call_data" => BorrowedToken::Keyword(noir_token::Keyword::CallData),
"char" => BorrowedToken::Keyword(noir_token::Keyword::Char),
"comptime" => BorrowedToken::Keyword(noir_token::Keyword::CompTime),
"comptime" => BorrowedToken::Keyword(noir_token::Keyword::Comptime),
"constrain" => BorrowedToken::Keyword(noir_token::Keyword::Constrain),
"continue" => BorrowedToken::Keyword(noir_token::Keyword::Continue),
"contract" => BorrowedToken::Keyword(noir_token::Keyword::Contract),
Expand Down
8 changes: 4 additions & 4 deletions compiler/noirc_frontend/src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,23 +532,23 @@ where
P2: ExprParser + 'a,
S: NoirParser<StatementKind> + 'a,
{
keyword(Keyword::CompTime)
keyword(Keyword::Comptime)
.ignore_then(choice((
declaration(expr),
for_loop(expr_no_constructors, statement.clone()),
block(statement).map_with_span(|block, span| {
StatementKind::Expression(Expression::new(ExpressionKind::Block(block), span))
}),
)))
.map(|statement| StatementKind::CompTime(Box::new(statement)))
.map(|statement| StatementKind::Comptime(Box::new(statement)))
}

/// Comptime in an expression position only accepts entire blocks
fn comptime_expr<'a, S>(statement: S) -> impl NoirParser<ExpressionKind> + 'a
where
S: NoirParser<StatementKind> + 'a,
{
keyword(Keyword::CompTime).ignore_then(block(statement)).map(ExpressionKind::Comptime)
keyword(Keyword::Comptime).ignore_then(block(statement)).map(ExpressionKind::Comptime)
}

fn declaration<'a, P>(expr_parser: P) -> impl NoirParser<StatementKind> + 'a
Expand Down Expand Up @@ -733,7 +733,7 @@ fn optional_distinctness() -> impl NoirParser<Distinctness> {
}

fn maybe_comp_time() -> impl NoirParser<bool> {
keyword(Keyword::CompTime).or_not().validate(|opt, span, emit| {
keyword(Keyword::Comptime).or_not().validate(|opt, span, emit| {
if opt.is_some() {
emit(ParserError::with_reason(
ParserErrorReason::ExperimentalFeature("comptime"),
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/parser/parser/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use chumsky::prelude::*;
use noirc_errors::Span;

fn maybe_comp_time() -> impl NoirParser<()> {
keyword(Keyword::CompTime).or_not().validate(|opt, span, emit| {
keyword(Keyword::Comptime).or_not().validate(|opt, span, emit| {
if opt.is_some() {
emit(ParserError::with_reason(ParserErrorReason::ComptimeDeprecated, span));
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ mod test {
HirStatement::Error => panic!("Invalid HirStatement!"),
HirStatement::Break => panic!("Unexpected break"),
HirStatement::Continue => panic!("Unexpected continue"),
HirStatement::CompTime(_) => panic!("Unexpected comptime"),
HirStatement::Comptime(_) => panic!("Unexpected comptime"),
};
let expr = interner.expression(&expr_id);

Expand Down
2 changes: 1 addition & 1 deletion tooling/nargo_fmt/src/visitor/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl super::FmtVisitor<'_> {
StatementKind::Error => unreachable!(),
StatementKind::Break => self.push_rewrite("break;".into(), span),
StatementKind::Continue => self.push_rewrite("continue;".into(), span),
StatementKind::CompTime(statement) => self.visit_stmt(*statement, span, is_last),
StatementKind::Comptime(statement) => self.visit_stmt(*statement, span, is_last),
}
}
}
Loading