initial attempt at a local sink on call

This commit is contained in:
PgBiel 2024-06-13 21:01:52 -03:00
parent e196e45c31
commit 3823f560c5
3 changed files with 85 additions and 26 deletions

View File

@ -325,22 +325,26 @@ impl Display for Tracepoint {
} }
} }
/// Enrich a [`SourceResult`] with a tracepoint. /// Enrich diagnostics with a tracepoint.
pub trait Trace<T> { pub trait Trace {
/// Add the tracepoint to all errors that lie outside the `span`. /// Add the tracepoint to all diagnostics that lie outside the `span`.
fn trace<F>(self, world: Tracked<dyn World + '_>, make_point: F, span: Span) -> Self fn trace<F>(self, world: Tracked<dyn World + '_>, make_point: F, span: Span) -> Self
where where
F: Fn() -> Tracepoint; F: Fn() -> Tracepoint;
} }
impl<T> Trace<T> for SourceResult<T> { impl Trace for EcoVec<SourceDiagnostic> {
fn trace<F>(self, world: Tracked<dyn World + '_>, make_point: F, span: Span) -> Self fn trace<F>(
mut self,
world: Tracked<dyn World + '_>,
make_point: F,
span: Span,
) -> Self
where where
F: Fn() -> Tracepoint, F: Fn() -> Tracepoint,
{ {
self.map_err(|mut errors| { let Some(trace_range) = world.range(span) else { return self };
let Some(trace_range) = world.range(span) else { return errors }; for error in self.make_mut().iter_mut() {
for error in errors.make_mut().iter_mut() {
// Skip traces that surround the error. // Skip traces that surround the error.
if let Some(error_range) = world.range(error.span) { if let Some(error_range) = world.range(error.span) {
if error.span.id() == span.id() if error.span.id() == span.id()
@ -353,8 +357,16 @@ impl<T> Trace<T> for SourceResult<T> {
error.trace.push(Spanned::new(make_point(), span)); error.trace.push(Spanned::new(make_point(), span));
} }
errors self
}) }
}
impl<T> Trace for SourceResult<T> {
fn trace<F>(self, world: Tracked<dyn World + '_>, make_point: F, span: Span) -> Self
where
F: Fn() -> Tracepoint,
{
self.map_err(|errors| errors.trace(world, make_point, span))
} }
} }

View File

@ -7,7 +7,7 @@ use comemo::{Track, Tracked, TrackedMut, Validate};
use ecow::EcoVec; use ecow::EcoVec;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use crate::diag::{self, Severity, SourceDiagnostic, SourceResult}; use crate::diag::{self, Severity, SourceDiagnostic, SourceResult, Trace, Tracepoint};
use crate::foundations::{Styles, Value}; use crate::foundations::{Styles, Value};
use crate::introspection::Introspector; use crate::introspection::Introspector;
use crate::syntax::{ast, FileId, Span}; use crate::syntax::{ast, FileId, Span};
@ -161,6 +161,30 @@ impl Sink {
self.values self.values
} }
/// Takes and returns all fields from this sink:
/// delayed errors, warnings and traced values.
pub fn take(
self,
) -> (
EcoVec<SourceDiagnostic>,
EcoVec<SourceDiagnostic>,
EcoVec<(Value, Option<Styles>)>,
) {
(self.delayed, self.warnings, self.values)
}
/// Adds a tracepoint to all warnings outside the given span.
pub fn trace_warnings<F>(
&mut self,
world: Tracked<dyn World + '_>,
make_point: F,
span: Span,
) where
F: Fn() -> Tracepoint,
{
self.warnings = std::mem::take(&mut self.warnings).trace(world, make_point, span);
}
/// Apply warning suppression. /// Apply warning suppression.
pub fn suppress_warnings(&mut self, world: &dyn World) { pub fn suppress_warnings(&mut self, world: &dyn World) {
self.warnings.retain(|diag| { self.warnings.retain(|diag| {
@ -204,7 +228,7 @@ impl Sink {
} }
/// Extend from another sink. /// Extend from another sink.
fn extend( pub fn extend(
&mut self, &mut self,
delayed: EcoVec<SourceDiagnostic>, delayed: EcoVec<SourceDiagnostic>,
warnings: EcoVec<SourceDiagnostic>, warnings: EcoVec<SourceDiagnostic>,

View File

@ -1,4 +1,4 @@
use comemo::{Tracked, TrackedMut}; use comemo::{Track, Tracked, TrackedMut};
use ecow::{eco_format, EcoVec}; use ecow::{eco_format, EcoVec};
use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint}; use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint};
@ -165,8 +165,31 @@ impl Eval for ast::FuncCall<'_> {
let point = || Tracepoint::Call(func.name().map(Into::into)); let point = || Tracepoint::Call(func.name().map(Into::into));
let f = || { let f = || {
func.call(&mut vm.engine, vm.context, args) // Create a temporary sink to accumulate all warnings produced by
.trace(vm.world(), point, span) // this call (either directly or due to a nested call). Later, we
// add a tracepoint to those warnings, indicating this call was
// part of the call stack that led to the warning being raised,
// thus allowing suppression of the warning through this call.
let mut local_sink = Sink::new();
let previous_sink =
std::mem::replace(&mut vm.engine.sink, local_sink.track_mut());
let call_result = func.call(&mut vm.engine, vm.context, args).trace(
vm.world(),
point,
span,
);
std::mem::replace(&mut vm.engine.sink, previous_sink);
local_sink.trace_warnings(vm.world(), point, span);
// Push the accumulated warnings and other fields back to the
// original sink after we have modified them. This is needed so the
// warnings are properly returned by compilation later.
let (delayed, warnings, values) = local_sink.take();
vm.engine.sink.extend(delayed, warnings, values);
call_result
}; };
// Stacker is broken on WASM. // Stacker is broken on WASM.