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

fix: Print comptime::Value better #5655

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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/comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl<'context> Elaborator<'context> {

if value != Value::Unit {
let items = value
.into_top_level_items(location)
.into_top_level_items(location, self.interner)
.map_err(|error| error.into_compilation_error_pair())?;

self.add_items(items, generated_items, location);
Expand Down
89 changes: 40 additions & 49 deletions compiler/noirc_frontend/src/hir/comptime/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,37 @@
use iter_extended::vecmap;
use noirc_errors::{CustomDiagnostic, Location};

use super::value::Value;

/// The possible errors that can halt the interpreter.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InterpreterError {
ArgumentCountMismatch { expected: usize, actual: usize, location: Location },
TypeMismatch { expected: Type, value: Value, location: Location },
TypeMismatch { expected: Type, actual: Type, location: Location },
NonComptimeVarReferenced { name: String, location: Location },
VariableNotInScope { location: Location },
IntegerOutOfRangeForType { value: FieldElement, typ: Type, location: Location },
ErrorNodeEncountered { location: Location },
NonFunctionCalled { value: Value, location: Location },
NonBoolUsedInIf { value: Value, location: Location },
NonBoolUsedInConstrain { value: Value, location: Location },
FailingConstraint { message: Option<Value>, location: Location },
NonFunctionCalled { typ: Type, location: Location },
NonBoolUsedInIf { typ: Type, location: Location },
NonBoolUsedInConstrain { typ: Type, location: Location },
FailingConstraint { message: Option<String>, location: Location },
NoMethodFound { name: String, typ: Type, location: Location },
NonIntegerUsedInLoop { value: Value, location: Location },
NonPointerDereferenced { value: Value, location: Location },
NonTupleOrStructInMemberAccess { value: Value, location: Location },
NonArrayIndexed { value: Value, location: Location },
NonIntegerUsedAsIndex { value: Value, location: Location },
NonIntegerUsedInLoop { typ: Type, location: Location },
NonPointerDereferenced { typ: Type, location: Location },
NonTupleOrStructInMemberAccess { typ: Type, location: Location },
NonArrayIndexed { typ: Type, location: Location },
NonIntegerUsedAsIndex { typ: Type, location: Location },
NonIntegerIntegerLiteral { typ: Type, location: Location },
NonIntegerArrayLength { typ: Type, location: Location },
NonNumericCasted { value: Value, location: Location },
NonNumericCasted { typ: Type, location: Location },
IndexOutOfBounds { index: usize, length: usize, location: Location },
ExpectedStructToHaveField { value: Value, field_name: String, location: Location },
ExpectedStructToHaveField { typ: Type, field_name: String, location: Location },
TypeUnsupported { typ: Type, location: Location },
InvalidValueForUnary { value: Value, operator: &'static str, location: Location },
InvalidValuesForBinary { lhs: Value, rhs: Value, operator: &'static str, location: Location },
InvalidValueForUnary { typ: Type, operator: &'static str, location: Location },
InvalidValuesForBinary { lhs: Type, rhs: Type, operator: &'static str, location: Location },
CastToNonNumericType { typ: Type, location: Location },
QuoteInRuntimeCode { location: Location },
NonStructInConstructor { typ: Type, location: Location },
CannotInlineMacro { value: Value, location: Location },
CannotInlineMacro { value: String, typ: Type, location: Location },
UnquoteFoundDuringEvaluation { location: Location },
DebugEvaluateComptime { diagnostic: CustomDiagnostic, location: Location },
FailedToParseMacro { error: ParserError, tokens: Rc<Tokens>, rule: &'static str, file: FileId },
Expand Down Expand Up @@ -170,9 +168,8 @@
let secondary = format!("Too {few_many} arguments");
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::TypeMismatch { expected, value, location } => {
let typ = value.get_type();
let msg = format!("Expected `{expected}` but a value of type `{typ}` was given");
InterpreterError::TypeMismatch { expected, actual, location } => {
let msg = format!("Expected `{expected}` but a value of type `{actual}` was given");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::NonComptimeVarReferenced { name, location } => {
Expand All @@ -198,23 +195,23 @@
let secondary = "This is a bug, please report this if found!".to_string();
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::NonFunctionCalled { value, location } => {
InterpreterError::NonFunctionCalled { typ, location } => {
let msg = "Only functions may be called".to_string();
let secondary = format!("Expression has type {}", value.get_type());
let secondary = format!("Expression has type {typ}");
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::NonBoolUsedInIf { value, location } => {
let msg = format!("Expected a `bool` but found `{}`", value.get_type());
InterpreterError::NonBoolUsedInIf { typ, location } => {
let msg = format!("Expected a `bool` but found `{typ}`");
let secondary = "If conditions must be a boolean value".to_string();
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::NonBoolUsedInConstrain { value, location } => {
let msg = format!("Expected a `bool` but found `{}`", value.get_type());
InterpreterError::NonBoolUsedInConstrain { typ, location } => {
let msg = format!("Expected a `bool` but found `{typ}`");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::FailingConstraint { message, location } => {
let (primary, secondary) = match message {
Some(msg) => (format!("{msg}"), "Assertion failed".into()),
Some(msg) => (msg.clone(), "Assertion failed".into()),
None => ("Assertion failed".into(), String::new()),
};
CustomDiagnostic::simple_error(primary, secondary, location.span)
Expand All @@ -223,32 +220,30 @@
let msg = format!("No method named `{name}` found for type `{typ}`");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::NonIntegerUsedInLoop { value, location } => {
let typ = value.get_type();
InterpreterError::NonIntegerUsedInLoop { typ, location } => {
let msg = format!("Non-integer type `{typ}` used in for loop");
let secondary = if matches!(typ.as_ref(), &Type::FieldElement) {
let secondary = if matches!(typ, Type::FieldElement) {
"`field` is not an integer type, try `u32` instead".to_string()
} else {
String::new()
};
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::NonPointerDereferenced { value, location } => {
let typ = value.get_type();
InterpreterError::NonPointerDereferenced { typ, location } => {
let msg = format!("Only references may be dereferenced, but found `{typ}`");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::NonTupleOrStructInMemberAccess { value, location } => {
let msg = format!("The type `{}` has no fields to access", value.get_type());
InterpreterError::NonTupleOrStructInMemberAccess { typ, location } => {
let msg = format!("The type `{typ}` has no fields to access");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::NonArrayIndexed { value, location } => {
let msg = format!("Expected an array or slice but found a(n) {}", value.get_type());
InterpreterError::NonArrayIndexed { typ, location } => {
let msg = format!("Expected an array or slice but found a(n) {typ}");
let secondary = "Only arrays or slices may be indexed".into();
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::NonIntegerUsedAsIndex { value, location } => {
let msg = format!("Expected an integer but found a(n) {}", value.get_type());
InterpreterError::NonIntegerUsedAsIndex { typ, location } => {
let msg = format!("Expected an integer but found a(n) {typ}");
let secondary =
"Only integers may be indexed. Note that this excludes `field`s".into();
CustomDiagnostic::simple_error(msg, secondary, location.span)
Expand All @@ -263,17 +258,16 @@
let secondary = "Array lengths must be integers".into();
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::NonNumericCasted { value, location } => {
InterpreterError::NonNumericCasted { typ, location } => {
let msg = "Only numeric types may be casted".into();
let secondary = format!("`{}` is non-numeric", value.get_type());
let secondary = format!("`{typ}` is non-numeric");
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::IndexOutOfBounds { index, length, location } => {
let msg = format!("{index} is out of bounds for the array of length {length}");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::ExpectedStructToHaveField { value, field_name, location } => {
let typ = value.get_type();
InterpreterError::ExpectedStructToHaveField { typ, field_name, location } => {
let msg = format!("The type `{typ}` has no field named `{field_name}`");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
Expand All @@ -282,13 +276,11 @@
format!("The type `{typ}` is currently unsupported in comptime expressions");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::InvalidValueForUnary { value, operator, location } => {
let msg = format!("`{}` cannot be used with unary {operator}", value.get_type());
InterpreterError::InvalidValueForUnary { typ, operator, location } => {
let msg = format!("`{typ}` cannot be used with unary {operator}");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::InvalidValuesForBinary { lhs, rhs, operator, location } => {
let lhs = lhs.get_type();
let rhs = rhs.get_type();
let msg = format!("No implementation for `{lhs}` {operator} `{rhs}`",);
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
Expand All @@ -304,10 +296,9 @@
let msg = format!("`{typ}` is not a struct type");
CustomDiagnostic::simple_error(msg, String::new(), location.span)
}
InterpreterError::CannotInlineMacro { value, location } => {
let typ = value.get_type();
InterpreterError::CannotInlineMacro { value, typ, location } => {
let msg = format!("Cannot inline values of type `{typ}` into this position");
let secondary = format!("Cannot inline value {value:?}");
let secondary = format!("Cannot inline value `{value}`");
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::UnquoteFoundDuringEvaluation { location } => {
Expand All @@ -320,7 +311,7 @@
let message = format!("Failed to parse macro's token stream into {rule}");
let tokens = vecmap(&tokens.0, ToString::to_string).join(" ");

// 10 is an aribtrary number of tokens here chosen to fit roughly onto one line

Check warning on line 314 in compiler/noirc_frontend/src/hir/comptime/errors.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (aribtrary)
let token_stream = if tokens.len() > 10 {
format!("The resulting token stream was: {tokens}")
} else {
Expand Down
Loading
Loading