Skip to content

Detect initial error instead of derivative one in context when layout does not converge #6175

@Andrew15-5

Description

@Andrew15-5

Description

#context {
  let c = counter(figure.where(kind: image))
  let n = c.get().first()
  [#figure[]<a>]
  // c.update(_ => n + 1)
  c.update(_ => () + 1)
}
@a

gives

warning: layout did not converge within 5 attempts
 = hint: check if any states or queries are updating themselves

error: label `<a>` does not exist in the document
  ┌─ file.typ:8:0
  │
8 │ @a
  │ ^^

But if I comment unused n variable creation, then it gives the initial error that caused the one above:

error: cannot add array and integer
  ┌─ file.typ:6:16
  │
6 │   c.update(_ => () + 1)
  │                 ^^^^^^

Which is really weird, since n is not used and therefore shouldn't affect anything, but with some context voodoo magic it does. This is a really bad UX, IMO.

Since closure body is not evaluated until it's called, I assume the label not fount error was hit earlier than the addition error, or maybe because the layout didn't converge the initial error just disappeared in the end or something like that.

This made debugging this kind of hard, since errors should be helping, but in this case it threw me away in a completely different direction from what I had to fix. I think Typst should try to prioritize helpful messages (so that we do not end up with C++ template level errors).

But I try to think what should be done here. Maybe a static analysis? Const evaluation? Expression optimizations? It feels very easily solvable if you have a constant expression that can be validated before executing anything. But if I write like I did at the start of debugging:

#context {
  let c = counter(figure.where(kind: image))
  let n = c.get()
  [#figure[]<a>]
  c.update(_ => n + 1)
}
@a

then it no longer static expression and it shows the same derivative error. So the only solution I see here is to .peek() into the closure body with known values and validate that as if it was const expression. But then again, it must be ignoring the error that it already detected, and keeps ignoring for 5 times and then just completely forgets about it. So maybe some priority needs to be changed or just keep a list of previous errors, and if you get error after not converging, you just print both initial and derivative error.

Use Case

Better UX.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdiagnosticsImprovements to compiler errors

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions