summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst/src/engine.rs48
-rw-r--r--crates/typst/src/eval/call.rs2
-rw-r--r--crates/typst/src/eval/mod.rs2
-rw-r--r--crates/typst/src/introspection/counter.rs2
-rw-r--r--crates/typst/src/introspection/state.rs2
-rw-r--r--crates/typst/src/layout/inline/mod.rs2
-rw-r--r--crates/typst/src/layout/mod.rs4
-rw-r--r--crates/typst/src/realize/mod.rs4
-rw-r--r--tests/typ/compiler/recursion.typ4
9 files changed, 37 insertions, 33 deletions
diff --git a/crates/typst/src/engine.rs b/crates/typst/src/engine.rs
index 189034cf..7d25bad3 100644
--- a/crates/typst/src/engine.rs
+++ b/crates/typst/src/engine.rs
@@ -8,9 +8,6 @@ use crate::introspection::{Introspector, Locator};
use crate::syntax::FileId;
use crate::World;
-/// The maxmium stack nesting depth.
-const MAX_DEPTH: usize = 64;
-
/// Holds all data needed during compilation.
pub struct Engine<'a> {
/// The compilation environment.
@@ -69,26 +66,28 @@ pub struct Route<'a> {
upper: Cell<usize>,
}
+/// The maximum nesting depths. They are different so that even if show rule and
+/// call checks are interleaved, show rule problems we always get the show rule.
+/// The lower the max depth for a kind of error, the higher its precedence
+/// compared to the others.
+impl Route<'_> {
+ /// The maximum stack nesting depth.
+ pub const MAX_SHOW_RULE_DEPTH: usize = 64;
+
+ /// The maxmium layout nesting depth.
+ pub const MAX_LAYOUT_DEPTH: usize = 72;
+
+ /// The maxmium function call nesting depth.
+ pub const MAX_CALL_DEPTH: usize = 80;
+}
+
impl<'a> Route<'a> {
/// Create a new, empty route.
pub fn root() -> Self {
Self { id: None, outer: None, len: 0, upper: Cell::new(0) }
}
- /// Insert a new id into the route.
- ///
- /// You must guarantee that `outer` lives longer than the resulting
- /// route is ever used.
- pub fn insert(outer: Tracked<'a, Self>, id: FileId) -> Self {
- Route {
- outer: Some(outer),
- id: Some(id),
- len: 0,
- upper: Cell::new(usize::MAX),
- }
- }
-
- /// Extend the route without another id.
+ /// Extend the route with another segment with a default length of 1.
pub fn extend(outer: Tracked<'a, Self>) -> Self {
Route {
outer: Some(outer),
@@ -98,6 +97,16 @@ impl<'a> Route<'a> {
}
}
+ /// Attach a file id to the route segment.
+ pub fn with_id(self, id: FileId) -> Self {
+ Self { id: Some(id), ..self }
+ }
+
+ /// Set the length of the route segment to zero.
+ pub fn unnested(self) -> Self {
+ Self { len: 0, ..self }
+ }
+
/// Start tracking this route.
///
/// In comparison to [`Track::track`], this method skips this chain link
@@ -118,11 +127,6 @@ impl<'a> Route<'a> {
pub fn decrease(&mut self) {
self.len -= 1;
}
-
- /// Check whether the nesting depth exceeds the limit.
- pub fn exceeding(&self) -> bool {
- !self.within(MAX_DEPTH)
- }
}
#[comemo::track]
diff --git a/crates/typst/src/eval/call.rs b/crates/typst/src/eval/call.rs
index 357d5e48..daa12cff 100644
--- a/crates/typst/src/eval/call.rs
+++ b/crates/typst/src/eval/call.rs
@@ -28,7 +28,7 @@ impl Eval for ast::FuncCall<'_> {
let args = self.args();
let trailing_comma = args.trailing_comma();
- if vm.engine.route.exceeding() {
+ if !vm.engine.route.within(Route::MAX_CALL_DEPTH) {
bail!(span, "maximum function call depth exceeded");
}
diff --git a/crates/typst/src/eval/mod.rs b/crates/typst/src/eval/mod.rs
index 9de4f1b7..d16f3204 100644
--- a/crates/typst/src/eval/mod.rs
+++ b/crates/typst/src/eval/mod.rs
@@ -53,7 +53,7 @@ pub fn eval(
let introspector = Introspector::default();
let engine = Engine {
world,
- route: Route::insert(route, id),
+ route: Route::extend(route).with_id(id),
introspector: introspector.track(),
locator: &mut locator,
tracer,
diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs
index ce485997..10960a85 100644
--- a/crates/typst/src/introspection/counter.rs
+++ b/crates/typst/src/introspection/counter.rs
@@ -277,7 +277,7 @@ impl Counter {
let mut engine = Engine {
world,
introspector,
- route: Route::extend(route),
+ route: Route::extend(route).unnested(),
locator: &mut locator,
tracer,
};
diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs
index 8479bace..382d8222 100644
--- a/crates/typst/src/introspection/state.rs
+++ b/crates/typst/src/introspection/state.rs
@@ -228,7 +228,7 @@ impl State {
let mut engine = Engine {
world,
introspector,
- route: Route::extend(route),
+ route: Route::extend(route).unnested(),
locator: &mut locator,
tracer,
};
diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs
index ba88f74e..6fcdd56d 100644
--- a/crates/typst/src/layout/inline/mod.rs
+++ b/crates/typst/src/layout/inline/mod.rs
@@ -28,7 +28,7 @@ use crate::text::{
use crate::util::Numeric;
use crate::World;
-/// Layout's content inline.
+/// Layouts content inline.
pub(crate) fn layout_inline(
children: &[Prehashed<Content>],
engine: &mut Engine,
diff --git a/crates/typst/src/layout/mod.rs b/crates/typst/src/layout/mod.rs
index dbdadbde..1af11856 100644
--- a/crates/typst/src/layout/mod.rs
+++ b/crates/typst/src/layout/mod.rs
@@ -182,7 +182,7 @@ impl LayoutRoot for Content {
let mut engine = Engine {
world,
introspector,
- route: Route::extend(route),
+ route: Route::extend(route).unnested(),
locator: &mut locator,
tracer,
};
@@ -237,7 +237,7 @@ impl Layout for Content {
tracer,
};
- if engine.route.exceeding() {
+ if !engine.route.within(Route::MAX_LAYOUT_DEPTH) {
bail!(
content.span(), "maximum layout depth exceeded";
hint: "try to reduce the amount of nesting in your layout",
diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs
index eda43b4d..1b204721 100644
--- a/crates/typst/src/realize/mod.rs
+++ b/crates/typst/src/realize/mod.rs
@@ -11,7 +11,7 @@ use smallvec::smallvec;
use typed_arena::Arena;
use crate::diag::{bail, SourceResult};
-use crate::engine::Engine;
+use crate::engine::{Engine, Route};
use crate::foundations::{
Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain,
StyleVecBuilder, Styles, Synthesize,
@@ -307,7 +307,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
if let Some(realized) = realize(self.engine, content, styles)? {
self.engine.route.increase();
- if self.engine.route.exceeding() {
+ if !self.engine.route.within(Route::MAX_SHOW_RULE_DEPTH) {
bail!(
content.span(), "maximum show rule depth exceeded";
hint: "check whether the show rule matches its own output";
diff --git a/tests/typ/compiler/recursion.typ b/tests/typ/compiler/recursion.typ
index 461680ab..ef5ea7e6 100644
--- a/tests/typ/compiler/recursion.typ
+++ b/tests/typ/compiler/recursion.typ
@@ -44,8 +44,8 @@
---
// Test cyclic imports during layout.
-// Error: 2-38 maximum layout depth exceeded
-// Hint: 2-38 try to reduce the amount of nesting in your layout
+// Error: 14-37 maximum layout depth exceeded
+// Hint: 14-37 try to reduce the amount of nesting in your layout
#layout(_ => include "recursion.typ")
---