Skip to content

Commit 63d58db

Browse files
committed
feat(rengine): output diagnostics in todo!s in printers
1 parent 88154d4 commit 63d58db

File tree

6 files changed

+75
-9
lines changed

6 files changed

+75
-9
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
Changes to the Rust Engine:
11+
- Printers now emit proper diagnostics (PR #1669)
12+
1013
## 0.3.4
1114

1215
The release of `0.3.3` got troubles because of the new Rust Engine crates.

rust-engine/src/ast/diagnostics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,6 @@ pub enum Context {
6868
Import,
6969
/// Error during the projection from idenitfiers to views
7070
NameView,
71+
/// Error in a printer
72+
Printer(String),
7173
}

rust-engine/src/backends/lean.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ impl Printer for LeanPrinter {
3030
binops::logical_op_or(),
3131
]))]
3232
}
33-
34-
const NAME: &str = "Lean";
3533
}
3634

3735
const INDENT: isize = 2;
@@ -94,6 +92,8 @@ const _: () = {
9492
macro_rules! concat {($($tt:tt)*) => {disambiguated_concat!($($tt)*)};}
9593

9694
impl<'a, 'b, A: 'a + Clone> PrettyAst<'a, 'b, A> for LeanPrinter {
95+
const NAME: &'static str = "Lean";
96+
9797
fn module(&'a self, module: &'b Module) -> DocBuilder<'a, Self, A> {
9898
let items = &module.items;
9999
docs![

rust-engine/src/backends/rust.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ impl Printer for RustPrinter {
1212
fn resugaring_phases() -> Vec<Box<dyn Resugaring>> {
1313
vec![]
1414
}
15-
16-
const NAME: &'static str = "Rust";
1715
}
1816

1917
const INDENT: isize = 4;
@@ -43,6 +41,8 @@ const _: () = {
4341
macro_rules! concat {($($tt:tt)*) => {disambiguated_concat!($($tt)*)};}
4442

4543
impl<'a, 'b, A: 'a + Clone> PrettyAst<'a, 'b, A> for RustPrinter {
44+
const NAME: &'static str = "Rust";
45+
4646
fn module(&'a self, module: &'b Module) -> DocBuilder<'a, Self, A> {
4747
intersperse!(&module.items, docs![hardline!(), hardline!()])
4848
}

rust-engine/src/printer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub trait Printer: Sized + for<'a, 'b> PrettyAst<'a, 'b, Span> + Default {
7878
/// A list of resugaring phases.
7979
fn resugaring_phases() -> Vec<Box<dyn Resugaring>>;
8080
/// The name of the printer
81-
const NAME: &'static str;
81+
const NAME: &'static str = <Self as PrettyAst<'static, 'static, Span>>::NAME;
8282
}
8383

8484
/// Placeholder type for sourcemaps.

rust-engine/src/printer/pretty_ast.rs

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,24 @@ impl<'a, 'b, A: 'a + Clone, P: PrettyAst<'a, 'b, A>, T: 'b + serde::Serialize> P
109109

110110
#[macro_export]
111111
/// Similar to [`std::todo`], but returns a document instead of panicking with a message.
112+
/// Also, `todo_document!` accepts a `issue #123` prefix to point to a specific issue number.
112113
macro_rules! todo_document {
114+
($allocator:ident, issue $issue:literal) => {
115+
{return $allocator.todo_document(&format!("TODO_LINE_{}", std::line!()), Some($issue));}
116+
};
117+
($allocator:ident, issue $issue:literal, $($tt:tt)*) => {
118+
{
119+
let message = format!($($tt)*);
120+
return $allocator.todo_document(&message, Some($issue));
121+
}
122+
};
113123
($allocator:ident,) => {
114-
{return $allocator.todo_document(&format!("TODO_LINE_{}", std::line!()));}
124+
{return $allocator.todo_document(&format!("TODO_LINE_{}", std::line!()), None);}
115125
};
116126
($allocator:ident, $($tt:tt)*) => {
117127
{
118128
let message = format!($($tt)*);
119-
return $allocator.todo_document(&message);
129+
return $allocator.todo_document(&message, None);
120130
}
121131
};
122132
}
@@ -157,6 +167,7 @@ macro_rules! install_pretty_helpers {
157167
$crate::printer::pretty_ast::install_pretty_helpers!(
158168
@$allocator,
159169
#[doc = ::std::concat!("Proxy macro for [`", stringify!($crate), "::printer::pretty_ast::todo_document`] that automatically uses `", stringify!($allocator),"` as allocator.")]
170+
#[doc = ::std::concat!(r#"Example: `disambiguated_todo!("Error message")` or `disambiguated_todo!(issue #123, "Error message with issue attached")`."#)]
160171
disambiguated_todo{$crate::printer::pretty_ast::todo_document!},
161172
#[doc = ::std::concat!("Proxy macro for [`pretty::docs`] that automatically uses `", stringify!($allocator),"` as allocator.")]
162173
docs{pretty::docs!},
@@ -203,6 +214,28 @@ macro_rules! install_pretty_helpers {
203214
}
204215
pub use install_pretty_helpers;
205216

217+
// This module tracks a span information via a global mutex, because our
218+
// printers cannot really carry information in a nice way. See issue
219+
// https://github.com/cryspen/hax/issues/1667. Once addressed this can go away.
220+
mod default_global_span_context {
221+
use super::Span;
222+
223+
use std::sync::{LazyLock, Mutex};
224+
static STATE: LazyLock<Mutex<Option<Span>>> = LazyLock::new(|| Mutex::new(None));
225+
226+
pub(super) fn with_span<T>(span: Span, action: impl Fn() -> T) -> T {
227+
let previous_span = STATE.lock().unwrap().clone();
228+
*STATE.lock().unwrap() = Some(span);
229+
let result = action();
230+
*STATE.lock().unwrap() = previous_span;
231+
result
232+
}
233+
234+
pub(super) fn get_ambiant_span() -> Option<Span> {
235+
STATE.lock().unwrap().clone()
236+
}
237+
}
238+
206239
macro_rules! mk {
207240
($($ty:ident),*) => {
208241
pastey::paste! {
@@ -237,10 +270,33 @@ macro_rules! mk {
237270
/// that implicitely use `self` as allocator. Take a look at a
238271
/// printer in the [`backends`] module for an example.
239272
pub trait PrettyAst<'a, 'b, A: 'a + Clone>: DocAllocator<'a, A> + Sized {
273+
/// A name for this instance of `PrettyAst`.
274+
/// Useful for diagnostics and debugging.
275+
const NAME: &'static str;
276+
277+
/// Emit a diagnostic with proper context and span.
278+
fn emit_diagnostic(&'a self, kind: hax_types::diagnostics::Kind) {
279+
let span = default_global_span_context::get_ambiant_span().unwrap_or_else(|| Span::dummy());
280+
use crate::printer::pretty_ast::diagnostics::{DiagnosticInfo, Context};
281+
(DiagnosticInfo {
282+
context: Context::Printer(Self::NAME.to_string()),
283+
span,
284+
kind
285+
}).emit()
286+
}
287+
240288
/// Produce a non-panicking placeholder document. In general, prefer the use of the helper macro [`todo_document!`].
241-
fn todo_document(&'a self, message: &str) -> DocBuilder<'a, Self, A> {
289+
fn todo_document(&'a self, message: &str, issue_id: Option<u32>) -> DocBuilder<'a, Self, A> {
290+
self.emit_diagnostic(hax_types::diagnostics::Kind::Unimplemented {
291+
issue_id,
292+
details: Some(message.into()),
293+
});
242294
self.as_string(message)
243295
}
296+
/// Execute an action with a span hint. Useful for errors.
297+
fn with_span<T>(&self, span: Span, action: impl Fn(&Self) -> T) -> T {
298+
default_global_span_context::with_span(span, || action(self))
299+
}
244300
/// Produce a structured error document for an unimplemented
245301
/// method.
246302
///
@@ -250,7 +306,12 @@ macro_rules! mk {
250306
/// of text that includes the method name and a JSON handle for
251307
/// the AST fragment (via [`DebugJSON`]).
252308
fn unimplemented_method(&'a self, method: &str, ast: ast::fragment::FragmentRef<'_>) -> DocBuilder<'a, Self, A> {
253-
self.text(format!("`{method}` unimpl, {}", DebugJSON(ast))).parens()
309+
let debug_json = DebugJSON(ast).to_string();
310+
self.emit_diagnostic(hax_types::diagnostics::Kind::Unimplemented {
311+
issue_id: None,
312+
details: Some(format!("The method `{method}` is not implemented in the backend {}. To show the AST fragment that could not be printed, run {debug_json}.", Self::NAME)),
313+
});
314+
self.text(format!("`{method}` unimpl, {debug_json}", )).parens()
254315
}
255316
$(
256317
#[doc = "Define how the printer formats a value of this AST type."]

0 commit comments

Comments
 (0)