Remove 'static bound on World

Thanks to improvements in comemo, tracked types don't need to be 'static anymore. This means that the 'static bound on the `World` is now lifted and that the `Route` doesn't need to use unsafe code anymore to manage its lifetime.
This commit is contained in:
Laurenz 2023-05-11 10:50:30 +02:00
parent d9ba84085e
commit 47dff3765d
20 changed files with 59 additions and 50 deletions

6
Cargo.lock generated
View File

@ -369,8 +369,7 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "comemo"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba423e212681b51c5452a458bb24e88165f4c09857a783c802719cc46313f3f"
source = "git+https://github.com/typst/comemo#0c141bbe47ca2d8c123fffc3f7f1ce35bb693993"
dependencies = [
"comemo-macros",
"siphasher",
@ -379,8 +378,7 @@ dependencies = [
[[package]]
name = "comemo-macros"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca5ceeb99665bad04a32fe297d1581a68685e36fb6da92a1c9b7d9693638c01"
source = "git+https://github.com/typst/comemo#0c141bbe47ca2d8c123fffc3f7f1ce35bb693993"
dependencies = [
"proc-macro2",
"quote",

View File

@ -36,7 +36,7 @@ bench = false
typst-macros = { path = "macros" }
bitflags = { version = "2", features = ["serde"] }
bytemuck = "1"
comemo = "0.2.2"
comemo = { git = "https://github.com/typst/comemo" }
ecow = "0.1"
flate2 = "1"
fontdb = "0.13"

View File

@ -25,7 +25,7 @@ typst-library = { path = "../library" }
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
clap = { version = "4.2.4", features = ["derive", "env"] }
codespan-reporting = "0.11"
comemo = "0.2.2"
comemo = { git = "https://github.com/typst/comemo" }
dirs = "5"
elsa = "1.8"
inferno = "0.11.15"

View File

@ -13,7 +13,7 @@ bench = false
[dependencies]
typst = { path = ".." }
typst-library = { path = "../library" }
comemo = "0.2.2"
comemo = { git = "https://github.com/typst/comemo" }
heck = "0.4"
include_dir = "0.7"
once_cell = "1"

View File

@ -19,7 +19,7 @@ bench = false
typst = { path = ".." }
az = "1.2"
chinese-number = { version = "0.7.2", default-features = false, features = ["number-to-chinese"] }
comemo = "0.2.2"
comemo = { git = "https://github.com/typst/comemo" }
csv = "1"
ecow = "0.1"
hayagriva = "0.3"

View File

@ -73,7 +73,7 @@ impl LayoutRoot for Content {
#[comemo::memoize]
fn cached(
content: &Content,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
tracer: TrackedMut<Tracer>,
provider: TrackedMut<StabilityProvider>,
introspector: Tracked<Introspector>,
@ -139,7 +139,7 @@ impl Layout for Content {
#[comemo::memoize]
fn cached(
content: &Content,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
tracer: TrackedMut<Tracer>,
provider: TrackedMut<StabilityProvider>,
introspector: Tracked<Introspector>,

View File

@ -139,7 +139,7 @@ impl ParElem {
#[allow(clippy::too_many_arguments)]
fn cached(
par: &ParElem,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
tracer: TrackedMut<Tracer>,
provider: TrackedMut<StabilityProvider>,
introspector: Tracked<Introspector>,

View File

@ -121,7 +121,7 @@ impl BibliographyElem {
/// Find all bibliography keys.
pub fn keys(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
) -> Vec<(EcoString, Option<EcoString>)> {
Self::find(introspector)
@ -426,7 +426,7 @@ impl Works {
/// Generate all citations and the whole bibliography.
#[comemo::memoize]
fn create(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
bibliography: BibliographyElem,
citations: Vec<CiteElem>,
) -> Arc<Works> {
@ -582,7 +582,7 @@ fn create(
/// Load bibliography entries from a path.
#[comemo::memoize]
fn load(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
paths: &BibPaths,
) -> StrResult<EcoVec<hayagriva::Entry>> {
let mut result = EcoVec::new();

View File

@ -405,7 +405,7 @@ impl Counter {
#[comemo::memoize]
fn sequence_impl(
&self,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
tracer: TrackedMut<Tracer>,
provider: TrackedMut<StabilityProvider>,
introspector: Tracked<Introspector>,

View File

@ -320,7 +320,7 @@ impl State {
#[comemo::memoize]
fn sequence_impl(
&self,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
tracer: TrackedMut<Tracer>,
provider: TrackedMut<StabilityProvider>,
introspector: Tracked<Introspector>,

View File

@ -448,8 +448,8 @@ impl Debug for ShapedText<'_> {
}
/// Holds shaping results and metadata common to all shaped segments.
struct ShapingContext<'a> {
vt: &'a Vt<'a>,
struct ShapingContext<'a, 'v> {
vt: &'a Vt<'v>,
spans: &'a SpanMapper,
glyphs: Vec<ShapedGlyph>,
used: Vec<Font>,

View File

@ -165,7 +165,7 @@ pub enum ImageFit {
/// Load an image from a path.
#[comemo::memoize]
fn load(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
full: &str,
fallback_family: Option<&str>,
alt: Option<EcoString>,

View File

@ -130,13 +130,13 @@ impl Display for Tracepoint {
/// Enrich a [`SourceResult`] with a tracepoint.
pub trait Trace<T> {
/// Add the tracepoint to all errors 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
F: Fn() -> Tracepoint;
}
impl<T> Trace<T> for SourceResult<T> {
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
F: Fn() -> Tracepoint,
{

View File

@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use comemo::{Prehashed, Track, Tracked, TrackedMut};
use comemo::{Prehashed, Tracked, TrackedMut};
use ecow::eco_format;
use once_cell::sync::Lazy;
@ -317,7 +317,7 @@ impl Closure {
#[allow(clippy::too_many_arguments)]
fn call(
this: &Func,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
route: Tracked<Route>,
tracer: TrackedMut<Tracer>,
provider: TrackedMut<StabilityProvider>,

View File

@ -67,7 +67,7 @@ pub struct LangItems {
/// The keys contained in the bibliography and short descriptions of them.
#[allow(clippy::type_complexity)]
pub bibliography_keys: fn(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
) -> Vec<(EcoString, Option<EcoString>)>,
/// A section heading: `= Introduction`.

View File

@ -41,7 +41,7 @@ use std::collections::HashSet;
use std::mem;
use std::path::{Path, PathBuf};
use comemo::{Track, Tracked, TrackedMut};
use comemo::{Track, Tracked, TrackedMut, Validate};
use ecow::{EcoString, EcoVec};
use unicode_segmentation::UnicodeSegmentation;
@ -67,7 +67,7 @@ const MAX_CALL_DEPTH: usize = 64;
#[comemo::memoize]
#[tracing::instrument(skip(world, route, tracer, source))]
pub fn eval(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
route: Tracked<Route>,
tracer: TrackedMut<Tracer>,
source: &Source,
@ -84,7 +84,7 @@ pub fn eval(
set_lang_items(library.items.clone());
// Evaluate the module.
let route = unsafe { Route::insert(route, id) };
let route = Route::insert(route, id);
let scopes = Scopes::new(Some(library));
let mut provider = StabilityProvider::new();
let introspector = Introspector::new(&[]);
@ -117,7 +117,7 @@ pub fn eval(
/// Everything in the output is associated with the given `span`.
#[comemo::memoize]
pub fn eval_string(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
code: &str,
span: Span,
) -> SourceResult<Value> {
@ -164,7 +164,7 @@ pub struct Vm<'a> {
/// The language items.
items: LangItems,
/// The route of source ids the VM took to reach its current location.
route: Tracked<'a, Route>,
route: Tracked<'a, Route<'a>>,
/// The current location.
location: SourceId,
/// A control flow event that is currently happening.
@ -200,7 +200,7 @@ impl<'a> Vm<'a> {
}
/// Access the underlying world.
pub fn world(&self) -> Tracked<'a, dyn World> {
pub fn world(&self) -> Tracked<'a, dyn World + 'a> {
self.vt.world
}
@ -263,34 +263,45 @@ impl Flow {
/// A route of source ids.
#[derive(Default)]
pub struct Route {
parent: Option<Tracked<'static, Self>>,
pub struct Route<'a> {
// We need to override the constraint's lifetime here so that `Tracked` is
// covariant over the constraint. If it becomes invariant, we're in for a
// world of lifetime pain.
outer: Option<Tracked<'a, Self, <Route<'static> as Validate>::Constraint>>,
id: Option<SourceId>,
}
impl Route {
impl<'a> Route<'a> {
/// Create a new route with just one entry.
pub fn new(id: SourceId) -> Self {
Self { id: Some(id), parent: None }
Self { id: Some(id), outer: None }
}
/// Insert a new id into the route.
///
/// You must guarantee that `outer` lives longer than the resulting
/// route is ever used.
unsafe fn insert(outer: Tracked<Route>, id: SourceId) -> Route {
Route {
parent: Some(std::mem::transmute(outer)),
id: Some(id),
pub fn insert(outer: Tracked<'a, Self>, id: SourceId) -> Self {
Route { outer: Some(outer), id: Some(id) }
}
/// Start tracking this locator.
///
/// In comparison to [`Track::track`], this method skips this chain link
/// if it does not contribute anything.
pub fn track(&self) -> Tracked<'_, Self> {
match self.outer {
Some(outer) if self.id.is_none() => outer,
_ => Track::track(self),
}
}
}
#[comemo::track]
impl Route {
impl<'a> Route<'a> {
/// Whether the given id is part of the route.
fn contains(&self, id: SourceId) -> bool {
self.id == Some(id) || self.parent.map_or(false, |parent| parent.contains(id))
self.id == Some(id) || self.outer.map_or(false, |outer| outer.contains(id))
}
}

View File

@ -53,7 +53,7 @@ impl Image {
pub fn with_fonts(
data: Buffer,
format: ImageFormat,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
fallback_family: Option<&str>,
alt: Option<EcoString>,
) -> StrResult<Self> {
@ -240,7 +240,7 @@ fn decode_svg(data: &Buffer) -> StrResult<Arc<DecodedImage>> {
#[comemo::memoize]
fn decode_svg_with_fonts(
data: &Buffer,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
fallback_family: Option<&str>,
) -> StrResult<Arc<DecodedImage>> {
let mut opts = usvg::Options::default();
@ -269,7 +269,7 @@ fn decode_svg_with_fonts(
/// Discover and load the fonts referenced by an SVG.
fn load_svg_fonts(
tree: &usvg::Tree,
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
fallback_family: Option<&str>,
) -> fontdb::Database {
let mut referenced = BTreeMap::<EcoString, bool>::new();

View File

@ -65,7 +65,7 @@ use crate::util::Buffer;
/// Compile a source file into a fully layouted document.
#[tracing::instrument(skip(world))]
pub fn compile(world: &(dyn World + 'static)) -> SourceResult<Document> {
pub fn compile(world: &dyn World) -> SourceResult<Document> {
// Evaluate the source file into a module.
let route = Route::default();
let mut tracer = Tracer::default();

View File

@ -14,7 +14,7 @@ pub use self::styles::*;
pub use typst_macros::element;
use comemo::{Constraint, Track, Tracked, TrackedMut};
use comemo::{Track, Tracked, TrackedMut, Validate};
use crate::diag::SourceResult;
use crate::doc::Document;
@ -25,7 +25,7 @@ use crate::World;
#[comemo::memoize]
#[tracing::instrument(skip(world, tracer, content))]
pub fn typeset(
world: Tracked<dyn World>,
world: Tracked<dyn World + '_>,
mut tracer: TrackedMut<Tracer>,
content: &Content,
) -> SourceResult<Document> {
@ -42,8 +42,8 @@ pub fn typeset(
loop {
tracing::info!("Layout iteration {iter}");
let constraint = Constraint::new();
let mut provider = StabilityProvider::new();
let constraint = <Introspector as Validate>::Constraint::new();
let mut vt = Vt {
world,
tracer: TrackedMut::reborrow_mut(&mut tracer),
@ -56,7 +56,7 @@ pub fn typeset(
introspector = Introspector::new(&document.pages);
if iter >= 5 || introspector.valid(&constraint) {
if iter >= 5 || introspector.validate(&constraint) {
break;
}
}
@ -69,7 +69,7 @@ pub fn typeset(
/// Holds the state needed to [typeset] content.
pub struct Vt<'a> {
/// The compilation environment.
pub world: Tracked<'a, dyn World>,
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.

View File

@ -9,7 +9,7 @@ publish = false
[dev-dependencies]
typst = { path = ".." }
typst-library = { path = "../library" }
comemo = "0.2.2"
comemo = { git = "https://github.com/typst/comemo" }
elsa = "1.8"
iai = { git = "https://github.com/reknih/iai" }
once_cell = "1"