From 378ebe5f5601f11c3f428c17bed492012feb251e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 12 Jun 2023 15:40:43 +0200 Subject: [PATCH] Delayed errors Fixes #785. Thanks to @Dherse for the idea! --- library/src/layout/mod.rs | 44 ++++++++++----- library/src/layout/par.rs | 19 +++++-- library/src/meta/bibliography.rs | 90 ++++++++++++++--------------- library/src/meta/context.rs | 10 ++-- library/src/meta/counter.rs | 74 +++++++++++++----------- library/src/meta/link.rs | 23 ++++---- library/src/meta/reference.rs | 94 ++++++++++++++++--------------- library/src/meta/state.rs | 37 +++++++----- src/eval/func.rs | 25 +++++--- src/eval/mod.rs | 19 ++++--- src/model/introspect.rs | 5 -- src/model/mod.rs | 56 ++++++++++++++++-- tests/ref/bugs/cite-locate.png | Bin 0 -> 50739 bytes tests/typ/bugs/cite-locate.typ | 23 ++++++++ 14 files changed, 315 insertions(+), 204 deletions(-) create mode 100644 tests/ref/bugs/cite-locate.png create mode 100644 tests/typ/bugs/cite-locate.typ diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs index d934c458e..41490eb8f 100644 --- a/library/src/layout/mod.rs +++ b/library/src/layout/mod.rs @@ -50,6 +50,7 @@ use std::mem; use typed_arena::Arena; use typst::diag::SourceResult; use typst::eval::Tracer; +use typst::model::DelayedErrors; use typst::model::{applicable, realize, StyleVecBuilder}; use crate::math::{EquationElem, LayoutMath}; @@ -116,13 +117,20 @@ impl LayoutRoot for Content { fn cached( content: &Content, world: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, styles: StyleChain, ) -> SourceResult { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, tracer, locator: &mut locator, introspector }; + let mut vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; let scratch = Scratch::default(); let (realized, styles) = realize_root(&mut vt, &scratch, content, styles)?; realized @@ -132,13 +140,13 @@ impl LayoutRoot for Content { } tracing::info!("Starting layout"); - cached( self, vt.world, - TrackedMut::reborrow_mut(&mut vt.tracer), - vt.locator.track(), vt.introspector, + vt.locator.track(), + TrackedMut::reborrow_mut(&mut vt.delayed), + TrackedMut::reborrow_mut(&mut vt.tracer), styles, ) } @@ -168,9 +176,10 @@ pub trait Layout { let mut locator = Locator::chained(vt.locator.track()); let mut vt = Vt { world: vt.world, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), - locator: &mut locator, introspector: vt.introspector, + locator: &mut locator, + tracer: TrackedMut::reborrow_mut(&mut vt.tracer), + delayed: TrackedMut::reborrow_mut(&mut vt.delayed), }; self.layout(&mut vt, styles, regions) } @@ -184,18 +193,26 @@ impl Layout for Content { styles: StyleChain, regions: Regions, ) -> SourceResult { + #[allow(clippy::too_many_arguments)] #[comemo::memoize] fn cached( content: &Content, world: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, styles: StyleChain, regions: Regions, ) -> SourceResult { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, tracer, locator: &mut locator, introspector }; + let mut vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; let scratch = Scratch::default(); let (realized, styles) = realize_block(&mut vt, &scratch, content, styles)?; realized @@ -209,9 +226,10 @@ impl Layout for Content { let fragment = cached( self, vt.world, - TrackedMut::reborrow_mut(&mut vt.tracer), - vt.locator.track(), vt.introspector, + vt.locator.track(), + TrackedMut::reborrow_mut(&mut vt.delayed), + TrackedMut::reborrow_mut(&mut vt.tracer), styles, regions, )?; diff --git a/library/src/layout/par.rs b/library/src/layout/par.rs index fa53f0317..2d0944ceb 100644 --- a/library/src/layout/par.rs +++ b/library/src/layout/par.rs @@ -5,6 +5,7 @@ use icu_provider_blob::BlobDataProvider; use icu_segmenter::{LineBreakIteratorUtf8, LineSegmenter}; use once_cell::sync::Lazy; use typst::eval::Tracer; +use typst::model::DelayedErrors; use unicode_bidi::{BidiInfo, Level as BidiLevel}; use unicode_script::{Script, UnicodeScript}; @@ -148,16 +149,23 @@ impl ParElem { fn cached( par: &ParElem, world: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, styles: StyleChain, consecutive: bool, region: Size, expand: bool, ) -> SourceResult { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, tracer, locator: &mut locator, introspector }; + let mut vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; let children = par.children(); // Collect all text into one string for BiDi analysis. @@ -178,9 +186,10 @@ impl ParElem { let fragment = cached( self, vt.world, - TrackedMut::reborrow_mut(&mut vt.tracer), - vt.locator.track(), vt.introspector, + vt.locator.track(), + TrackedMut::reborrow_mut(&mut vt.delayed), + TrackedMut::reborrow_mut(&mut vt.tracer), styles, consecutive, region, diff --git a/library/src/meta/bibliography.rs b/library/src/meta/bibliography.rs index 737530b8b..f020f730a 100644 --- a/library/src/meta/bibliography.rs +++ b/library/src/meta/bibliography.rs @@ -96,11 +96,11 @@ impl BibliographyElem { pub fn find(introspector: Tracked) -> StrResult { let mut iter = introspector.query(&Self::func().select()).into_iter(); let Some(elem) = iter.next() else { - return Err("the document does not contain a bibliography".into()); + bail!("the document does not contain a bibliography"); }; if iter.next().is_some() { - Err("multiple bibliographies are not supported")?; + bail!("multiple bibliographies are not supported"); } Ok(elem.to::().unwrap().clone()) @@ -162,42 +162,40 @@ impl Show for BibliographyElem { seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack()); } - if !vt.introspector.init() { - return Ok(Content::sequence(seq)); - } + Ok(vt.delayed(|vt| { + let works = Works::new(vt).at(self.span())?; - let works = Works::new(vt).at(self.span())?; + let row_gutter = BlockElem::below_in(styles).amount(); + if works.references.iter().any(|(prefix, _)| prefix.is_some()) { + let mut cells = vec![]; + for (prefix, reference) in &works.references { + cells.push(prefix.clone().unwrap_or_default()); + cells.push(reference.clone()); + } - let row_gutter = BlockElem::below_in(styles).amount(); - if works.references.iter().any(|(prefix, _)| prefix.is_some()) { - let mut cells = vec![]; - for (prefix, reference) in &works.references { - cells.push(prefix.clone().unwrap_or_default()); - cells.push(reference.clone()); + seq.push(VElem::new(row_gutter).with_weakness(3).pack()); + seq.push( + GridElem::new(cells) + .with_columns(TrackSizings(vec![Sizing::Auto; 2])) + .with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()])) + .with_row_gutter(TrackSizings(vec![row_gutter.into()])) + .pack(), + ); + } else { + let mut entries = vec![]; + for (_, reference) in &works.references { + entries.push(VElem::new(row_gutter).with_weakness(3).pack()); + entries.push(reference.clone()); + } + + seq.push( + Content::sequence(entries) + .styled(ParElem::set_hanging_indent(INDENT.into())), + ); } - seq.push(VElem::new(row_gutter).with_weakness(3).pack()); - seq.push( - GridElem::new(cells) - .with_columns(TrackSizings(vec![Sizing::Auto; 2])) - .with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()])) - .with_row_gutter(TrackSizings(vec![row_gutter.into()])) - .pack(), - ); - } else { - let mut entries = vec![]; - for (_, reference) in &works.references { - entries.push(VElem::new(row_gutter).with_weakness(3).pack()); - entries.push(reference.clone()); - } - - seq.push( - Content::sequence(entries) - .styled(ParElem::set_hanging_indent(INDENT.into())), - ); - } - - Ok(Content::sequence(seq)) + Ok(Content::sequence(seq)) + })) } } @@ -357,19 +355,17 @@ impl Synthesize for CiteElem { impl Show for CiteElem { #[tracing::instrument(name = "CiteElem::show", skip(self, vt))] fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult { - if !vt.introspector.init() { - return Ok(Content::empty()); - } - - let works = Works::new(vt).at(self.span())?; - let location = self.0.location().unwrap(); - works - .citations - .get(&location) - .cloned() - .flatten() - .ok_or("bibliography does not contain this key") - .at(self.span()) + Ok(vt.delayed(|vt| { + let works = Works::new(vt).at(self.span())?; + let location = self.0.location().unwrap(); + works + .citations + .get(&location) + .cloned() + .flatten() + .ok_or("bibliography does not contain this key") + .at(self.span()) + })) } } diff --git a/library/src/meta/context.rs b/library/src/meta/context.rs index d599c63e3..2ed359ee4 100644 --- a/library/src/meta/context.rs +++ b/library/src/meta/context.rs @@ -73,12 +73,10 @@ struct LocateElem { impl Show for LocateElem { #[tracing::instrument(name = "LocateElem::show", skip(self, vt))] fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult { - if !vt.introspector.init() { - return Ok(Content::empty()); - } - - let location = self.0.location().unwrap(); - Ok(self.func().call_vt(vt, [location])?.display()) + Ok(vt.delayed(|vt| { + let location = self.0.location().unwrap(); + Ok(self.func().call_vt(vt, [location])?.display()) + })) } } diff --git a/library/src/meta/counter.rs b/library/src/meta/counter.rs index ef4646ab2..65522c403 100644 --- a/library/src/meta/counter.rs +++ b/library/src/meta/counter.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use ecow::{eco_vec, EcoVec}; use smallvec::{smallvec, SmallVec}; use typst::eval::Tracer; +use typst::model::DelayedErrors; use super::{FigureElem, HeadingElem, Numbering, NumberingPattern}; use crate::layout::PageElem; @@ -397,9 +398,10 @@ impl Counter { ) -> SourceResult> { self.sequence_impl( vt.world, - TrackedMut::reborrow_mut(&mut vt.tracer), - vt.locator.track(), vt.introspector, + vt.locator.track(), + TrackedMut::reborrow_mut(&mut vt.delayed), + TrackedMut::reborrow_mut(&mut vt.tracer), ) } @@ -408,12 +410,19 @@ impl Counter { fn sequence_impl( &self, world: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, ) -> SourceResult> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, tracer, locator: &mut locator, introspector }; + let mut vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; let mut state = CounterState(match &self.0 { // special case, because pages always start at one. CounterKey::Page => smallvec![1], @@ -618,37 +627,36 @@ struct DisplayElem { impl Show for DisplayElem { #[tracing::instrument(name = "DisplayElem::show", skip_all)] fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult { - if !vt.introspector.init() { - return Ok(Content::empty()); - } + Ok(vt.delayed(|vt| { + let location = self.0.location().unwrap(); + let counter = self.counter(); + let numbering = self + .numbering() + .or_else(|| { + let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else { + return None; + }; - let location = self.0.location().unwrap(); - let counter = self.counter(); - let numbering = self - .numbering() - .or_else(|| { - let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else { - return None; + if func == HeadingElem::func() { + HeadingElem::numbering_in(styles) + } else if func == FigureElem::func() { + FigureElem::numbering_in(styles) + } else if func == EquationElem::func() { + EquationElem::numbering_in(styles) + } else { + None + } + }) + .unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into()); + + let state = if self.both() { + counter.both(vt, location)? + } else { + counter.at(vt, location)? }; - if func == HeadingElem::func() { - HeadingElem::numbering_in(styles) - } else if func == FigureElem::func() { - FigureElem::numbering_in(styles) - } else if func == EquationElem::func() { - EquationElem::numbering_in(styles) - } else { - None - } - }) - .unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into()); - - let state = if self.both() { - counter.both(vt, location)? - } else { - counter.at(vt, location)? - }; - state.display(vt, &numbering) + state.display(vt, &numbering) + })) } } diff --git a/library/src/meta/link.rs b/library/src/meta/link.rs index 43f6a34d6..c3d8718c9 100644 --- a/library/src/meta/link.rs +++ b/library/src/meta/link.rs @@ -91,21 +91,18 @@ impl Show for LinkElem { #[tracing::instrument(name = "LinkElem::show", skip(self, vt))] fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult { let body = self.body(); - let dest = match self.dest() { - LinkTarget::Dest(dest) => dest, - LinkTarget::Label(label) => { - if !vt.introspector.init() { - return Ok(body); - } - - let elem = vt.introspector.query_label(&label).at(self.span())?; - Destination::Location(elem.location().unwrap()) - } + let linked = match self.dest() { + LinkTarget::Dest(dest) => body.linked(dest), + LinkTarget::Label(label) => vt + .delayed(|vt| { + let elem = vt.introspector.query_label(&label).at(self.span())?; + let dest = Destination::Location(elem.location().unwrap()); + Ok(Some(body.clone().linked(dest))) + }) + .unwrap_or(body), }; - Ok(body - .linked(dest) - .styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false))))) + Ok(linked.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false))))) } } diff --git a/library/src/meta/reference.rs b/library/src/meta/reference.rs index 5a295e335..96358ffa8 100644 --- a/library/src/meta/reference.rs +++ b/library/src/meta/reference.rs @@ -132,7 +132,7 @@ impl Synthesize for RefElem { self.push_element(None); let target = self.target(); - if vt.introspector.init() && !BibliographyElem::has(vt, &target.0) { + if !BibliographyElem::has(vt, &target.0) { if let Ok(elem) = vt.introspector.query_label(&target) { self.push_element(Some(elem.into_inner())); return Ok(()); @@ -146,63 +146,65 @@ impl Synthesize for RefElem { impl Show for RefElem { #[tracing::instrument(name = "RefElem::show", skip_all)] fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult { - if !vt.introspector.init() { - return Ok(Content::empty()); - } + Ok(vt.delayed(|vt| { + let target = self.target(); + let elem = vt.introspector.query_label(&self.target()); + let span = self.span(); - let target = self.target(); - let elem = vt.introspector.query_label(&self.target()); - let span = self.span(); + if BibliographyElem::has(vt, &target.0) { + if elem.is_ok() { + bail!(span, "label occurs in the document and its bibliography"); + } - if BibliographyElem::has(vt, &target.0) { - if elem.is_ok() { - bail!(span, "label occurs in the document and its bibliography"); + return Ok(self.to_citation(vt, styles)?.pack().spanned(span)); } - return Ok(self.to_citation(vt, styles)?.pack().spanned(span)); - } + let elem = elem.at(span)?; + let refable = elem + .with::() + .ok_or_else(|| { + if elem.can::() { + eco_format!( + "cannot reference {} directly, try putting it into a figure", + elem.func().name() + ) + } else { + eco_format!("cannot reference {}", elem.func().name()) + } + }) + .at(span)?; - let elem = elem.at(span)?; - let refable = elem - .with::() - .ok_or_else(|| { - if elem.can::() { + let numbering = refable + .numbering() + .ok_or_else(|| { eco_format!( - "cannot reference {} directly, try putting it into a figure", + "cannot reference {0} without numbering \ + - did you mean to use `#set {0}(numbering: \"1.\")`?", elem.func().name() ) - } else { - eco_format!("cannot reference {}", elem.func().name()) + }) + .at(span)?; + + let numbers = refable + .counter() + .at(vt, elem.location().unwrap())? + .display(vt, &numbering.trimmed())?; + + let supplement = match self.supplement(styles) { + Smart::Auto => refable.supplement(), + Smart::Custom(None) => Content::empty(), + Smart::Custom(Some(supplement)) => { + supplement.resolve(vt, [(*elem).clone()])? } - }) - .at(span)?; + }; - let numbering = refable - .numbering() - .ok_or_else(|| { - eco_format!("cannot reference {0} without numbering - did you mean to use `#set {0}(numbering: \"1.\")`?", elem.func().name()) - }) - .at(span)?; - - let numbers = refable - .counter() - .at(vt, elem.location().unwrap())? - .display(vt, &numbering.trimmed())?; - - let supplement = match self.supplement(styles) { - Smart::Auto => refable.supplement(), - Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => { - supplement.resolve(vt, [(*elem).clone()])? + let mut content = numbers; + if !supplement.is_empty() { + content = supplement + TextElem::packed("\u{a0}") + content; } - }; - let mut content = numbers; - if !supplement.is_empty() { - content = supplement + TextElem::packed("\u{a0}") + content; - } - - Ok(content.linked(Destination::Location(elem.location().unwrap()))) + Ok(content.linked(Destination::Location(elem.location().unwrap()))) + })) } } diff --git a/library/src/meta/state.rs b/library/src/meta/state.rs index 231852e30..a8e37901b 100644 --- a/library/src/meta/state.rs +++ b/library/src/meta/state.rs @@ -2,6 +2,7 @@ use std::fmt::{self, Debug, Formatter, Write}; use ecow::{eco_vec, EcoVec}; use typst::eval::Tracer; +use typst::model::DelayedErrors; use crate::prelude::*; @@ -306,9 +307,10 @@ impl State { fn sequence(&self, vt: &mut Vt) -> SourceResult> { self.sequence_impl( vt.world, - TrackedMut::reborrow_mut(&mut vt.tracer), - vt.locator.track(), vt.introspector, + vt.locator.track(), + TrackedMut::reborrow_mut(&mut vt.delayed), + TrackedMut::reborrow_mut(&mut vt.tracer), ) } @@ -317,12 +319,19 @@ impl State { fn sequence_impl( &self, world: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, ) -> SourceResult> { let mut locator = Locator::chained(locator); - let mut vt = Vt { world, tracer, locator: &mut locator, introspector }; + let mut vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; let mut state = self.init.clone(); let mut stops = eco_vec![state.clone()]; @@ -397,16 +406,14 @@ struct DisplayElem { impl Show for DisplayElem { #[tracing::instrument(name = "DisplayElem::show", skip(self, vt))] fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult { - if !vt.introspector.init() { - return Ok(Content::empty()); - } - - let location = self.0.location().unwrap(); - let value = self.state().at(vt, location)?; - Ok(match self.func() { - Some(func) => func.call_vt(vt, [value])?.display(), - None => value.display(), - }) + Ok(vt.delayed(|vt| { + let location = self.0.location().unwrap(); + let value = self.state().at(vt, location)?; + Ok(match self.func() { + Some(func) => func.call_vt(vt, [value])?.display(), + None => value.display(), + }) + })) } } diff --git a/src/eval/func.rs b/src/eval/func.rs index 1745dfb1a..28d4a40df 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -11,7 +11,7 @@ use super::{ Value, Vm, }; use crate::diag::{bail, SourceResult, StrResult}; -use crate::model::{ElemFunc, Introspector, Locator, Vt}; +use crate::model::{DelayedErrors, ElemFunc, Introspector, Locator, Vt}; use crate::syntax::ast::{self, AstNode, Expr, Ident}; use crate::syntax::{SourceId, Span, SyntaxNode}; use crate::World; @@ -102,9 +102,10 @@ impl Func { self, vm.world(), route, - TrackedMut::reborrow_mut(&mut vm.vt.tracer), - vm.vt.locator.track(), vm.vt.introspector, + vm.vt.locator.track(), + TrackedMut::reborrow_mut(&mut vm.vt.delayed), + TrackedMut::reborrow_mut(&mut vm.vt.tracer), vm.depth + 1, args, ) @@ -129,9 +130,10 @@ impl Func { let mut locator = Locator::chained(vt.locator.track()); let vt = Vt { world: vt.world, - tracer: TrackedMut::reborrow_mut(&mut vt.tracer), - locator: &mut locator, introspector: vt.introspector, + locator: &mut locator, + delayed: TrackedMut::reborrow_mut(&mut vt.delayed), + tracer: TrackedMut::reborrow_mut(&mut vt.tracer), }; let mut vm = Vm::new(vt, route.track(), id, scopes); let args = Args::new(self.span(), args); @@ -326,9 +328,10 @@ impl Closure { this: &Func, world: Tracked, route: Tracked, - tracer: TrackedMut, - locator: Tracked, introspector: Tracked, + locator: Tracked, + delayed: TrackedMut, + tracer: TrackedMut, depth: usize, mut args: Args, ) -> SourceResult { @@ -344,7 +347,13 @@ impl Closure { // Prepare VT. let mut locator = Locator::chained(locator); - let vt = Vt { world, tracer, locator: &mut locator, introspector }; + let vt = Vt { + world, + introspector, + locator: &mut locator, + delayed, + tracer, + }; // Prepare VM. let mut vm = Vm::new(vt, route, closure.location, scopes); diff --git a/src/eval/mod.rs b/src/eval/mod.rs index e60162186..fe11606ae 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -62,9 +62,6 @@ use ecow::{EcoString, EcoVec}; use unicode_segmentation::UnicodeSegmentation; use self::func::{CapturesVisitor, Closure}; -use crate::diag::{ - bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint, -}; use crate::model::{ Content, Introspector, Label, Locator, Recipe, ShowableSelector, Styles, Transform, Unlabellable, Vt, @@ -75,6 +72,10 @@ use crate::syntax::{ }; use crate::util::PathExt; use crate::World; +use crate::{ + diag::{bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint}, + model::DelayedErrors, +}; const MAX_ITERATIONS: usize = 10_000; const MAX_CALL_DEPTH: usize = 64; @@ -102,11 +103,13 @@ pub fn eval( // Prepare VT. let mut locator = Locator::default(); let introspector = Introspector::default(); + let mut delayed = DelayedErrors::default(); let vt = Vt { world, - tracer, - locator: &mut locator, introspector: introspector.track(), + locator: &mut locator, + delayed: delayed.track_mut(), + tracer, }; // Prepare VM. @@ -151,12 +154,14 @@ pub fn eval_string( // Prepare VT. let mut tracer = Tracer::default(); let mut locator = Locator::default(); + let mut delayed = DelayedErrors::default(); let introspector = Introspector::default(); let vt = Vt { world, - tracer: tracer.track_mut(), - locator: &mut locator, introspector: introspector.track(), + locator: &mut locator, + delayed: delayed.track_mut(), + tracer: tracer.track_mut(), }; // Prepare VM. diff --git a/src/model/introspect.rs b/src/model/introspect.rs index f00f89f50..b150fabff 100644 --- a/src/model/introspect.rs +++ b/src/model/introspect.rs @@ -241,11 +241,6 @@ impl Introspector { #[comemo::track] impl Introspector { - /// Whether this introspector is not yet initialized. - pub fn init(&self) -> bool { - self.pages > 0 - } - /// Query for all matching elements. pub fn query(&self, selector: &Selector) -> EcoVec> { let hash = crate::util::hash128(selector); diff --git a/src/model/mod.rs b/src/model/mod.rs index 632b691fe..ee9402361 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -28,7 +28,7 @@ use std::mem::ManuallyDrop; use comemo::{Track, Tracked, TrackedMut, Validate}; -use crate::diag::SourceResult; +use crate::diag::{SourceError, SourceResult}; use crate::doc::Document; use crate::eval::Tracer; use crate::World; @@ -46,8 +46,9 @@ pub fn typeset( let library = world.library(); let styles = StyleChain::new(&library.styles); - let mut document; let mut iter = 0; + let mut document; + let mut delayed; // We need `ManuallyDrop` until this lands in stable: // https://github.com/rust-lang/rust/issues/70919 @@ -58,6 +59,8 @@ pub fn typeset( loop { tracing::info!("Layout iteration {iter}"); + delayed = DelayedErrors::default(); + let constraint = ::Constraint::new(); let mut locator = Locator::new(); let mut vt = Vt { @@ -65,6 +68,7 @@ pub fn typeset( tracer: TrackedMut::reborrow_mut(&mut tracer), locator: &mut locator, introspector: introspector.track_with(&constraint), + delayed: delayed.track_mut(), }; // Layout! @@ -86,6 +90,11 @@ pub fn typeset( // Drop the introspector. ManuallyDrop::into_inner(introspector); + // Promote delayed errors. + if !delayed.0.is_empty() { + return Err(Box::new(delayed.0)); + } + Ok(document) } @@ -95,10 +104,45 @@ pub fn typeset( pub struct Vt<'a> { /// The compilation environment. pub world: Tracked<'a, dyn World + 'a>, - /// The tracer for inspection of the values an expression produces. - pub tracer: TrackedMut<'a, Tracer>, - /// Provides stable identities to elements. - pub locator: &'a mut Locator<'a>, /// Provides access to information about the document. pub introspector: Tracked<'a, Introspector>, + /// Provides stable identities to elements. + pub locator: &'a mut Locator<'a>, + /// Delayed errors that do not immediately terminate execution. + pub delayed: TrackedMut<'a, DelayedErrors>, + /// The tracer for inspection of the values an expression produces. + pub tracer: TrackedMut<'a, Tracer>, +} + +impl Vt<'_> { + /// Perform a fallible operation that does not immediately terminate further + /// execution. Instead it produces a delayed error that is only promoted to + /// a fatal one if it remains at the end of the introspection loop. + pub fn delayed(&mut self, f: F) -> T + where + F: FnOnce(&mut Self) -> SourceResult, + T: Default, + { + match f(self) { + Ok(value) => value, + Err(errors) => { + for error in *errors { + self.delayed.push(error); + } + T::default() + } + } + } +} + +/// Holds delayed errors. +#[derive(Default, Clone)] +pub struct DelayedErrors(Vec); + +#[comemo::track] +impl DelayedErrors { + /// Push a delayed error. + fn push(&mut self, error: SourceError) { + self.0.push(error); + } } diff --git a/tests/ref/bugs/cite-locate.png b/tests/ref/bugs/cite-locate.png new file mode 100644 index 0000000000000000000000000000000000000000..396726f3b86668ea8ab75da271e7c6527e1dc80d GIT binary patch literal 50739 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 literal 0 HcmV?d00001 diff --git a/tests/typ/bugs/cite-locate.typ b/tests/typ/bugs/cite-locate.typ new file mode 100644 index 000000000..c3786c5fc --- /dev/null +++ b/tests/typ/bugs/cite-locate.typ @@ -0,0 +1,23 @@ +// Test citation in other introspection. + +--- +#set page(width: 180pt) +#set heading(numbering: "1") + +#outline( + title: [List of Figures], + target: figure.where(kind: image), +) + +#pagebreak() + += Introduction +#figure( + rect[-- PIRATE --], + caption: [A pirate @arrgh in @intro], +) + +#locate(loc => [Citation @distress on page #loc.page()]) + +#pagebreak() +#bibliography("/works.bib", style: "chicago-notes")