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

feat: add std::warn::warn #7723

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
25 changes: 25 additions & 0 deletions compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ use crate::{
node_interner::{
DefinitionId, DefinitionInfo, DefinitionKind, ExprId, FuncId, GlobalId, TraitImplKind,
},
token::FunctionAttribute,
};

use super::{Elaborator, ResolverMeta, path_resolution::PathResolutionItem};
@@ -572,6 +573,8 @@ impl Elaborator<'_> {
}
}

self.check_call_to_warn_builtin_at_runtime(&definition_kind, location);

let id = self.interner.push_expr(HirExpression::Ident(expr.clone(), generics.clone()));

self.interner.push_expr_location(id, location);
@@ -597,6 +600,28 @@ impl Elaborator<'_> {
}
}

// It's an error to call to the built-in function "warn" if we are not in a comptime context
fn check_call_to_warn_builtin_at_runtime(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not covered by how we disallow calling comptime functions from a runtime context?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you are right. However, that check happens during monomorphization (not sure why!) and before that it panics when it can't find the built-in in SSA generation. That said, I guess I'll introduce this built-in in SSA that does nothing to let monomorphization produce this error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... but monomorphization happens before SSA, I don't know why it goes to SSA with errors 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aah... it's because built-in functions don't go through the monomorphizer's queue.

Would it be okay to move this error from monomorphization to where I put it? (generalize it to all comptime functions, not just warn).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm stopping for the day so we can discuss next week. You can workaround this with a non-builtin wrapper function which is comptime - this will ensure that the error is thrown appropriately.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! And that explains why we have many wrappers like that.

But... it didn't work. The reason is that the warning is then produced in the std crate, and we don't show warnings if they aren't from the crate being compiled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh that means that this feature isn't going to work for Nico's usage anyway

&mut self,
definition_kind: &Option<DefinitionKind>,
location: Location,
) {
let Some(DefinitionKind::Function(func_id)) = definition_kind else {
return;
};

if self.in_comptime_context() {
return;
}

let attribute = self.interner.function_attributes(func_id).function();
if let Some(FunctionAttribute::Builtin(builtin)) = attribute {
if builtin == "warn" {
self.push_err(ResolverError::WarnUsedAtRuntime { location });
}
}
}

/// Solve any generics that are part of the path before the function, for example:
///
/// foo::Bar::<i32>::baz
10 changes: 9 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/errors.rs
Original file line number Diff line number Diff line change
@@ -256,6 +256,10 @@ pub enum InterpreterError {
LoopHaltedForUiResponsiveness {
location: Location,
},
Warning {
message: String,
location: Location,
},

// These cases are not errors, they are just used to prevent us from running more code
// until the loop can be resumed properly. These cases will never be displayed to users.
@@ -331,7 +335,8 @@ impl InterpreterError {
| InterpreterError::UnknownArrayLength { location, .. }
| InterpreterError::CannotInterpretFormatStringWithErrors { location }
| InterpreterError::GlobalsDependencyCycle { location }
| InterpreterError::LoopHaltedForUiResponsiveness { location } => *location,
| InterpreterError::LoopHaltedForUiResponsiveness { location }
| InterpreterError::Warning { location, .. } => *location,

InterpreterError::FailedToParseMacro { error, .. } => error.location(),
InterpreterError::NoMatchingImplFound { error } => error.location,
@@ -695,6 +700,9 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic {
"This error doesn't happen in normal executions of `nargo`".to_string();
CustomDiagnostic::simple_warning(msg, secondary, *location)
}
InterpreterError::Warning { message, location } => {
CustomDiagnostic::simple_warning(message.into(), String::new(), *location)
}
}
}
}
13 changes: 13 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
@@ -248,6 +248,7 @@ impl Interpreter<'_, '_> {
"unresolved_type_is_bool" => unresolved_type_is_bool(interner, arguments, location),
"unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location),
"unresolved_type_is_unit" => unresolved_type_is_unit(interner, arguments, location),
"warn" => warn(self.elaborator, arguments, location),
"zeroed" => Ok(zeroed(return_type, location)),
_ => {
let item = format!("Comptime evaluation for builtin function '{name}'");
@@ -1403,6 +1404,18 @@ where
Ok(option(return_type, option_value, location))
}

// fn warn<T, let N: u32>(message: fmtstr<N, T>) {}
fn warn(
elaborator: &mut Elaborator,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let message = check_one_argument(arguments, location)?;
let (message, _) = get_format_string(elaborator.interner, message)?;
elaborator.push_err(InterpreterError::Warning { message: message.to_string(), location });
Ok(Value::Unit)
}

// fn zeroed<T>() -> T
fn zeroed(return_type: Type, location: Location) -> Value {
match return_type {
14 changes: 11 additions & 3 deletions compiler/noirc_frontend/src/hir/resolution/errors.rs
Original file line number Diff line number Diff line change
@@ -192,6 +192,8 @@ pub enum ResolverError {
UnexpectedItemInPattern { location: Location, item: &'static str },
#[error("Trait `{trait_name}` doesn't have a method named `{method_name}`")]
NoSuchMethodInTrait { trait_name: String, method_name: String, location: Location },
#[error("The `std::warn::warn` function cannot be called at runtime")]
WarnUsedAtRuntime { location: Location },
}

impl ResolverError {
@@ -255,9 +257,8 @@ impl ResolverError {
| ResolverError::TypeUnsupportedInMatch { location, .. }
| ResolverError::UnexpectedItemInPattern { location, .. }
| ResolverError::NoSuchMethodInTrait { location, .. }
| ResolverError::VariableAlreadyDefinedInPattern { new_location: location, .. } => {
*location
}
| ResolverError::VariableAlreadyDefinedInPattern { new_location: location, .. }
| ResolverError::WarnUsedAtRuntime { location } => *location,
ResolverError::UnusedVariable { ident }
| ResolverError::UnusedItem { ident, .. }
| ResolverError::DuplicateField { field: ident }
@@ -801,6 +802,13 @@ impl<'a> From<&'a ResolverError> for Diagnostic {
*location,
)
},
ResolverError::WarnUsedAtRuntime {location } => {
Diagnostic::simple_error(
"The `std::warn::warn` function cannot be called at runtime".to_string(),
"This function can only be called in comptime code".to_string(),
*location,
)
},
}
}
}
1 change: 1 addition & 0 deletions noir_stdlib/src/lib.nr
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ pub mod append;
pub mod mem;
pub mod panic;
pub mod hint;
pub mod warn;

use convert::AsPrimitive;

5 changes: 5 additions & 0 deletions noir_stdlib/src/warn.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Produces a warning during compilation.
///
/// Note: this function cannot be used at runtime.
#[builtin(warn)]
pub comptime fn warn<T, let N: u32>(message: fmtstr<N, T>) {}
Loading