From c5c73ec9315b8148e851693ffa279c75a97982d3 Mon Sep 17 00:00:00 2001
From: Malo <57839069+MDLC01@users.noreply.github.com>
Date: Thu, 18 Apr 2024 14:20:05 +0200
Subject: [PATCH] Fix compiler panic on stack with infinite spacing (#3918)
---
crates/typst/src/layout/grid/layout.rs | 4 +++
crates/typst/src/layout/stack.rs | 36 +++++++++++++++++++-------
tests/suite/layout/grid/grid.typ | 9 +++++++
tests/suite/layout/stack.typ | 9 +++++++
4 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/crates/typst/src/layout/grid/layout.rs b/crates/typst/src/layout/grid/layout.rs
index 6dbe151e6..398ad1bdc 100644
--- a/crates/typst/src/layout/grid/layout.rs
+++ b/crates/typst/src/layout/grid/layout.rs
@@ -2692,6 +2692,10 @@ impl<'a> GridLayouter<'a> {
height: Abs,
y: usize,
) -> SourceResult {
+ if !self.width.is_finite() {
+ bail!(self.span, "cannot create grid with infinite width");
+ }
+
if !height.is_finite() {
bail!(self.span, "cannot create grid with infinite height");
}
diff --git a/crates/typst/src/layout/stack.rs b/crates/typst/src/layout/stack.rs
index caa78264a..05b415faf 100644
--- a/crates/typst/src/layout/stack.rs
+++ b/crates/typst/src/layout/stack.rs
@@ -1,6 +1,7 @@
use std::fmt::{self, Debug, Formatter};
+use typst_syntax::Span;
-use crate::diag::SourceResult;
+use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{cast, elem, Content, Packed, Resolve, StyleChain, StyledElem};
use crate::layout::{
@@ -59,7 +60,8 @@ impl LayoutMultiple for Packed {
styles: StyleChain,
regions: Regions,
) -> SourceResult {
- let mut layouter = StackLayouter::new(self.dir(styles), regions, styles);
+ let mut layouter =
+ StackLayouter::new(self.span(), self.dir(styles), regions, styles);
let axis = layouter.dir.axis();
// Spacing to insert before the next block.
@@ -97,7 +99,7 @@ impl LayoutMultiple for Packed {
}
}
- Ok(layouter.finish())
+ layouter.finish()
}
}
@@ -131,6 +133,8 @@ cast! {
/// Performs stack layout.
struct StackLayouter<'a> {
+ /// The span to raise errors at during layout.
+ span: Span,
/// The stacking direction.
dir: Dir,
/// The axis of the stacking direction.
@@ -166,7 +170,12 @@ enum StackItem {
impl<'a> StackLayouter<'a> {
/// Create a new stack layouter.
- fn new(dir: Dir, mut regions: Regions<'a>, styles: StyleChain<'a>) -> Self {
+ fn new(
+ span: Span,
+ dir: Dir,
+ mut regions: Regions<'a>,
+ styles: StyleChain<'a>,
+ ) -> Self {
let axis = dir.axis();
let expand = regions.expand;
@@ -174,6 +183,7 @@ impl<'a> StackLayouter<'a> {
regions.expand.set(axis, false);
Self {
+ span,
dir,
axis,
regions,
@@ -218,7 +228,7 @@ impl<'a> StackLayouter<'a> {
styles: StyleChain,
) -> SourceResult<()> {
if self.regions.is_full() {
- self.finish_region();
+ self.finish_region()?;
}
// Block-axis alignment of the `AlignElement` is respected by stacks.
@@ -251,7 +261,7 @@ impl<'a> StackLayouter<'a> {
self.items.push(StackItem::Frame(frame, align));
if i + 1 < len {
- self.finish_region();
+ self.finish_region()?;
}
}
@@ -259,7 +269,7 @@ impl<'a> StackLayouter<'a> {
}
/// Advance to the next region.
- fn finish_region(&mut self) {
+ fn finish_region(&mut self) -> SourceResult<()> {
// Determine the size of the stack in this region depending on whether
// the region expands.
let mut size = self
@@ -275,6 +285,10 @@ impl<'a> StackLayouter<'a> {
size.set(self.axis, full);
}
+ if !size.is_finite() {
+ bail!(self.span, "stack spacing is infinite");
+ }
+
let mut output = Frame::hard(size);
let mut cursor = Abs::zero();
let mut ruler: FixedAlignment = self.dir.start().into();
@@ -320,12 +334,14 @@ impl<'a> StackLayouter<'a> {
self.used = Gen::zero();
self.fr = Fr::zero();
self.finished.push(output);
+
+ Ok(())
}
/// Finish layouting and return the resulting frames.
- fn finish(mut self) -> Fragment {
- self.finish_region();
- Fragment::frames(self.finished)
+ fn finish(mut self) -> SourceResult {
+ self.finish_region()?;
+ Ok(Fragment::frames(self.finished))
}
}
diff --git a/tests/suite/layout/grid/grid.typ b/tests/suite/layout/grid/grid.typ
index f4f0b90a7..2d45095d8 100644
--- a/tests/suite/layout/grid/grid.typ
+++ b/tests/suite/layout/grid/grid.typ
@@ -274,3 +274,12 @@ The following:
[],
[a]
)
+
+--- issue-3917-grid-with-infinite-width ---
+// https://github.com/typst/typst/issues/1918
+#set page(width: auto)
+#context layout(available => {
+ let infinite-length = available.width
+ // Error: 3-50 cannot create grid with infinite width
+ grid(gutter: infinite-length, columns: 2)[A][B]
+})
diff --git a/tests/suite/layout/stack.typ b/tests/suite/layout/stack.typ
index 1eca52c99..aad273a5b 100644
--- a/tests/suite/layout/stack.typ
+++ b/tests/suite/layout/stack.typ
@@ -80,3 +80,12 @@ World! 🌍
stack([a], 1fr, [b]),
stack([a], v(1fr), [b]),
)
+
+--- issue-1918-stack-with-infinite-spacing ---
+// https://github.com/typst/typst/issues/1918
+#set page(width: auto)
+#context layout(available => {
+ let infinite-length = available.width
+ // Error: 3-40 stack spacing is infinite
+ stack(spacing: infinite-length)[A][B]
+})