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] +})