Repository: typst/typst
File: crates/typst/src/eval/markup.rs (Rust)

Code before:
        match expr {
            ast::Expr::Set(set) => {
                let styles = set.eval(vm)?;
                if vm.flow.is_some() {
                    break;
                }

                seq.push(eval_markup(vm, exprs)?.styled_with_map(styles))
            }
            ast::Expr::Show(show) => {
                let recipe = show.eval(vm)?;
                if vm.flow.is_some() {
                    break;
                }

                let tail = eval_markup(vm, exprs)?;
                seq.push(tail.styled_with_recipe(&mut vm.engine, vm.context, recipe)?)
            }
            expr => match expr.eval(vm)? {
                Value::Label(label) => {
                    if let Some(elem) =
                        seq.iter_mut().rev().find(|node| !node.can::<dyn Unlabellable>())
                    {
                        if let Some(prev_label) = elem.label() {
                            vm.engine.sink.warn(warning!(
                                prev_label_expr.unwrap().span(),
                                "label `{}` has been ignored",
                                prev_label.repr()
                            ));
                        }

                        *elem = std::mem::take(elem).labelled(label);
                        prev_label_expr = Some(expr);
                    } else {
                        vm.engine.sink.warn(warning!(
                            expr.span(),
                            "label `{}` is not attached to anything",
                            label.repr()
                        ));
                    }
                }
                value => seq.push(value.display().spanned(expr.span())),
            },
        }

        if vm.flow.is_some() {
            break;
        }
    }

    if flow.is_some() {

Review comment (suggestion):
I think this unwrap can panic in practice. The previous label needn't come from the same content block, it could have been applied anywhere in a different function call. 

Code after:
            ast::Expr::Set(set) => {
                let styles = set.eval(vm)?;
                if vm.flow.is_some() {
                    break;
                }

                seq.push(eval_markup(vm, exprs)?.styled_with_map(styles))
            }
            ast::Expr::Show(show) => {
                let recipe = show.eval(vm)?;
                if vm.flow.is_some() {
                    break;
                }

                let tail = eval_markup(vm, exprs)?;
                seq.push(tail.styled_with_recipe(&mut vm.engine, vm.context, recipe)?)
            }
            expr => match expr.eval(vm)? {
                Value::Label(label) => {
                    if let Some(elem) =
                        seq.iter_mut().rev().find(|node| !node.can::<dyn Unlabellable>())
                    {
                        if elem.label().is_some() {
                            vm.engine.sink.warn(warning!(
                                elem.span(), "content labelled multiple times";
                                hint: "only the last label is used, the rest are ignored",
                            ));
                        }

                        *elem = std::mem::take(elem).labelled(label);
                    } else {
                        vm.engine.sink.warn(warning!(
                            expr.span(),
                            "label `{}` is not attached to anything",
                            label.repr()
                        ));
                    }
                }
                value => seq.push(value.display().spanned(expr.span())),
            },
        }

        if vm.flow.is_some() {
            break;
        }
    }

    if flow.is_some() {
        vm.flow = flow;
    }