From 3823f560c548d5f09e3485b39c3a0ae124f7b2c3 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:01:52 -0300 Subject: [PATCH] initial attempt at a local sink on call --- crates/typst/src/diag.rs | 54 +++++++++++++++++++++-------------- crates/typst/src/engine.rs | 28 ++++++++++++++++-- crates/typst/src/eval/call.rs | 29 +++++++++++++++++-- 3 files changed, 85 insertions(+), 26 deletions(-) diff --git a/crates/typst/src/diag.rs b/crates/typst/src/diag.rs index de52957fb..b906f5504 100644 --- a/crates/typst/src/diag.rs +++ b/crates/typst/src/diag.rs @@ -325,36 +325,48 @@ impl Display for Tracepoint { } } -/// Enrich a [`SourceResult`] with a tracepoint. -pub trait Trace { - /// Add the tracepoint to all errors that lie outside the `span`. +/// Enrich diagnostics with a tracepoint. +pub trait Trace { + /// Add the tracepoint to all diagnostics that lie outside the `span`. fn trace(self, world: Tracked, make_point: F, span: Span) -> Self where F: Fn() -> Tracepoint; } -impl Trace for SourceResult { +impl Trace for EcoVec { + fn trace( + mut self, + world: Tracked, + make_point: F, + span: Span, + ) -> Self + where + F: Fn() -> Tracepoint, + { + let Some(trace_range) = world.range(span) else { return self }; + for error in self.make_mut().iter_mut() { + // Skip traces that surround the error. + if let Some(error_range) = world.range(error.span) { + if error.span.id() == span.id() + && trace_range.start <= error_range.start + && trace_range.end >= error_range.end + { + continue; + } + } + + error.trace.push(Spanned::new(make_point(), span)); + } + self + } +} + +impl Trace for SourceResult { fn trace(self, world: Tracked, make_point: F, span: Span) -> Self where F: Fn() -> Tracepoint, { - self.map_err(|mut errors| { - let Some(trace_range) = world.range(span) else { return errors }; - for error in errors.make_mut().iter_mut() { - // Skip traces that surround the error. - if let Some(error_range) = world.range(error.span) { - if error.span.id() == span.id() - && trace_range.start <= error_range.start - && trace_range.end >= error_range.end - { - continue; - } - } - - error.trace.push(Spanned::new(make_point(), span)); - } - errors - }) + self.map_err(|errors| errors.trace(world, make_point, span)) } } diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs index d506fe7e0..09772e176 100644 --- a/crates/typst/src/engine.rs +++ b/crates/typst/src/engine.rs @@ -7,7 +7,7 @@ use comemo::{Track, Tracked, TrackedMut, Validate}; use ecow::EcoVec; 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::introspection::Introspector; use crate::syntax::{ast, FileId, Span}; @@ -161,6 +161,30 @@ impl Sink { self.values } + /// Takes and returns all fields from this sink: + /// delayed errors, warnings and traced values. + pub fn take( + self, + ) -> ( + EcoVec, + EcoVec, + EcoVec<(Value, Option)>, + ) { + (self.delayed, self.warnings, self.values) + } + + /// Adds a tracepoint to all warnings outside the given span. + pub fn trace_warnings( + &mut self, + world: Tracked, + 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. pub fn suppress_warnings(&mut self, world: &dyn World) { self.warnings.retain(|diag| { @@ -204,7 +228,7 @@ impl Sink { } /// Extend from another sink. - fn extend( + pub fn extend( &mut self, delayed: EcoVec, warnings: EcoVec, diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs index a143c8ac2..11a59a787 100644 --- a/crates/typst/src/eval/call.rs +++ b/crates/typst/src/eval/call.rs @@ -1,4 +1,4 @@ -use comemo::{Tracked, TrackedMut}; +use comemo::{Track, Tracked, TrackedMut}; use ecow::{eco_format, EcoVec}; 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 f = || { - func.call(&mut vm.engine, vm.context, args) - .trace(vm.world(), point, span) + // Create a temporary sink to accumulate all warnings produced by + // 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.