Skip to content

Commit

Permalink
feat: add CLI argument for debugging comptime blocks (#5192)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves #5168

## Summary\*



## Additional Context

- Restores `hir_to_ast` pass as `hir_to_display_ast` from
https://github.com/noir-lang/noir/pull/5147/files
+ Only using it for display is much easier than trying to go back and
forth between HIR and the AST

## Documentation\*

Check one:
- [x] No documentation needed.
- [ ] 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: Tom French <15848336+TomAFrench@users.noreply.github.com>
Co-authored-by: jfecher <jake@aztecprotocol.com>
  • Loading branch information
3 people authored Jul 10, 2024
1 parent 93d937e commit 0b74a18
Show file tree
Hide file tree
Showing 29 changed files with 758 additions and 73 deletions.
1 change: 1 addition & 0 deletions compiler/fm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ license.workspace = true

[dependencies]
codespan-reporting.workspace = true
iter-extended.workspace = true
serde.workspace = true

[dev-dependencies]
Expand Down
21 changes: 21 additions & 0 deletions compiler/fm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod file_map;

pub use file_map::{File, FileId, FileMap, PathString};

use iter_extended::vecmap;
// Re-export for the lsp
pub use codespan_reporting::files as codespan_files;

Expand Down Expand Up @@ -103,6 +104,26 @@ impl FileManager {
pub fn name_to_id(&self, file_name: PathBuf) -> Option<FileId> {
self.file_map.get_file_id(&PathString::from_path(file_name))
}

/// Find a file by its path suffix, e.g. "src/main.nr" is a suffix of
/// "some_dir/package_name/src/main.nr"`
pub fn find_by_path_suffix(&self, suffix: &str) -> Result<Option<FileId>, Vec<PathBuf>> {
let suffix_path: Vec<_> = Path::new(suffix).components().rev().collect();
let results: Vec<_> = self
.path_to_id
.iter()
.filter(|(path, _id)| {
path.components().rev().zip(suffix_path.iter()).all(|(x, y)| &x == y)
})
.collect();
if results.is_empty() {
Ok(None)
} else if results.len() == 1 {
Ok(Some(*results[0].1))
} else {
Err(vecmap(results, |(path, _id)| path.clone()))
}
}
}

pub trait NormalizePath {
Expand Down
11 changes: 10 additions & 1 deletion compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ pub struct CompileOptions {
#[arg(long, hide = true)]
pub use_legacy: bool,

/// Enable printing results of comptime evaluation: provide a path suffix
/// for the module to debug, e.g. "package_name/src/main.nr"
#[arg(long)]
pub debug_comptime_in_file: Option<String>,

/// Outputs the paths to any modified artifacts
#[arg(long, hide = true)]
pub show_artifact_paths: bool,
Expand Down Expand Up @@ -258,12 +263,14 @@ pub fn check_crate(
deny_warnings: bool,
disable_macros: bool,
use_legacy: bool,
debug_comptime_in_file: Option<&str>,
) -> CompilationResult<()> {
let macros: &[&dyn MacroProcessor] =
if disable_macros { &[] } else { &[&aztec_macros::AztecMacro as &dyn MacroProcessor] };

let mut errors = vec![];
let diagnostics = CrateDefMap::collect_defs(crate_id, context, use_legacy, macros);
let diagnostics =
CrateDefMap::collect_defs(crate_id, context, use_legacy, debug_comptime_in_file, macros);
errors.extend(diagnostics.into_iter().map(|(error, file_id)| {
let diagnostic = CustomDiagnostic::from(&error);
diagnostic.in_file(file_id)
Expand Down Expand Up @@ -301,6 +308,7 @@ pub fn compile_main(
options.deny_warnings,
options.disable_macros,
options.use_legacy,
options.debug_comptime_in_file.as_deref(),
)?;

let main = context.get_main_function(&crate_id).ok_or_else(|| {
Expand Down Expand Up @@ -342,6 +350,7 @@ pub fn compile_contract(
options.deny_warnings,
options.disable_macros,
options.use_legacy,
options.debug_comptime_in_file.as_deref(),
)?;

// TODO: We probably want to error if contracts is empty
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_driver/tests/stdlib_warnings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn stdlib_does_not_produce_constant_warnings() -> Result<(), ErrorsAndWarnings>
let root_crate_id = prepare_crate(&mut context, file_name);

let ((), warnings) =
noirc_driver::check_crate(&mut context, root_crate_id, false, false, false)?;
noirc_driver::check_crate(&mut context, root_crate_id, false, false, false, None)?;

assert_eq!(warnings, Vec::new(), "stdlib is producing {} warnings", warnings.len());

Expand Down
49 changes: 41 additions & 8 deletions compiler/noirc_errors/src/reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum DiagnosticKind {
Error,
Bug,
Warning,
Info,
}

/// A count of errors that have been already reported to stderr
Expand All @@ -37,30 +38,57 @@ impl CustomDiagnostic {
}
}

pub fn simple_error(
fn simple_with_kind(
primary_message: String,
secondary_message: String,
secondary_span: Span,
kind: DiagnosticKind,
) -> CustomDiagnostic {
CustomDiagnostic {
message: primary_message,
secondaries: vec![CustomLabel::new(secondary_message, secondary_span)],
notes: Vec::new(),
kind: DiagnosticKind::Error,
kind,
}
}

pub fn simple_error(
primary_message: String,
secondary_message: String,
secondary_span: Span,
) -> CustomDiagnostic {
Self::simple_with_kind(
primary_message,
secondary_message,
secondary_span,
DiagnosticKind::Error,
)
}

pub fn simple_warning(
primary_message: String,
secondary_message: String,
secondary_span: Span,
) -> CustomDiagnostic {
CustomDiagnostic {
message: primary_message,
secondaries: vec![CustomLabel::new(secondary_message, secondary_span)],
notes: Vec::new(),
kind: DiagnosticKind::Warning,
}
Self::simple_with_kind(
primary_message,
secondary_message,
secondary_span,
DiagnosticKind::Warning,
)
}

pub fn simple_info(
primary_message: String,
secondary_message: String,
secondary_span: Span,
) -> CustomDiagnostic {
Self::simple_with_kind(
primary_message,
secondary_message,
secondary_span,
DiagnosticKind::Info,
)
}

pub fn simple_bug(
Expand Down Expand Up @@ -96,6 +124,10 @@ impl CustomDiagnostic {
matches!(self.kind, DiagnosticKind::Warning)
}

pub fn is_info(&self) -> bool {
matches!(self.kind, DiagnosticKind::Info)
}

pub fn is_bug(&self) -> bool {
matches!(self.kind, DiagnosticKind::Bug)
}
Expand Down Expand Up @@ -191,6 +223,7 @@ fn convert_diagnostic(
) -> Diagnostic<fm::FileId> {
let diagnostic = match (cd.kind, deny_warnings) {
(DiagnosticKind::Warning, false) => Diagnostic::warning(),
(DiagnosticKind::Info, _) => Diagnostic::note(),
(DiagnosticKind::Bug, ..) => Diagnostic::bug(),
_ => Diagnostic::error(),
};
Expand Down
42 changes: 26 additions & 16 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ use crate::{
UnresolvedTypeExpression,
},
hir::{
comptime::{self, Interpreter, InterpreterError},
comptime::{self, InterpreterError},
resolution::{errors::ResolverError, resolver::LambdaContext},
type_check::TypeCheckError,
},
hir_def::{
expr::{
HirArrayLiteral, HirBinaryOp, HirBlockExpression, HirCallExpression, HirCastExpression,
HirConstructorExpression, HirIfExpression, HirIndexExpression, HirInfixExpression,
HirLambda, HirMemberAccess, HirMethodCallExpression, HirMethodReference,
HirPrefixExpression,
HirConstructorExpression, HirExpression, HirIfExpression, HirIndexExpression,
HirInfixExpression, HirLambda, HirMemberAccess, HirMethodCallExpression,
HirMethodReference, HirPrefixExpression,
},
traits::TraitConstraint,
},
macros_api::{
BlockExpression, CallExpression, CastExpression, Expression, ExpressionKind, HirExpression,
HirLiteral, HirStatement, Ident, IndexExpression, Literal, MemberAccessExpression,
BlockExpression, CallExpression, CastExpression, Expression, ExpressionKind, HirLiteral,
HirStatement, Ident, IndexExpression, Literal, MemberAccessExpression,
MethodCallExpression, PrefixExpression,
},
node_interner::{DefinitionKind, ExprId, FuncId, ReferenceId},
Expand Down Expand Up @@ -674,12 +674,20 @@ impl<'context> Elaborator<'context> {
// call is not yet solved for.
self.function_context.push(Default::default());
let (block, _typ) = self.elaborate_block_expression(block);
self.check_and_pop_function_context();

let mut interpreter =
Interpreter::new(self.interner, &mut self.comptime_scopes, self.crate_id);
self.check_and_pop_function_context();
let mut interpreter_errors = vec![];
let mut interpreter = self.setup_interpreter(&mut interpreter_errors);
let value = interpreter.evaluate_block(block);
self.inline_comptime_value(value, span)
self.include_interpreter_errors(interpreter_errors);
let (id, typ) = self.inline_comptime_value(value, span);

let location = self.interner.id_location(id);
self.debug_comptime(location, |interner| {
interner.expression(&id).to_display_ast(interner, location.span).kind
});

(id, typ)
}

pub(super) fn inline_comptime_value(
Expand Down Expand Up @@ -750,9 +758,9 @@ impl<'context> Elaborator<'context> {
}
};

let mut interpreter =
Interpreter::new(self.interner, &mut self.comptime_scopes, self.crate_id);

let file = self.file;
let mut interpreter_errors = vec![];
let mut interpreter = self.setup_interpreter(&mut interpreter_errors);
let mut comptime_args = Vec::new();
let mut errors = Vec::new();

Expand All @@ -762,17 +770,19 @@ impl<'context> Elaborator<'context> {
let location = interpreter.interner.expr_location(&argument);
comptime_args.push((arg, location));
}
Err(error) => errors.push((error.into(), self.file)),
Err(error) => errors.push((error.into(), file)),
}
}

let bindings = interpreter.interner.get_instantiation_bindings(func).clone();
let result = interpreter.call_function(function, comptime_args, bindings, location);
self.include_interpreter_errors(interpreter_errors);

if !errors.is_empty() {
self.errors.append(&mut errors);
return None;
}

let bindings = interpreter.interner.get_instantiation_bindings(func).clone();
let result = interpreter.call_function(function, comptime_args, bindings, location);
let (expr_id, typ) = self.inline_comptime_value(result, location.span);
Some((self.interner.expression(&expr_id), typ))
}
Expand Down
Loading

0 comments on commit 0b74a18

Please sign in to comment.