Summary
Lowering errors carry a source span (LowerError { message, span: Option<Span> }), and perry check renders it as a proper error[CODE] --> file:line:col diagnostic. But perry compile prints only the bare message with no location. On large/minified/generated inputs this makes any lowering wall effectively undiagnosable — you get a one-line error with no way to find the offending construct.
Repro
Same input, two front-ends:
// t.ts
for (var { a, b } = { a: 1, b: 2 }, i = 0; i < 1; i++) console.log(a, b, i);
$ perry check t.ts
error[U006]: Unsupported binding pattern
--> t.ts:1:11
1 | for (var { a, b } = { a: 1, b: 2 }, i = 0; i < 1; i++) console.log(a, b, i);
| ^
$ perry compile t.ts -o /tmp/out
Error: Unsupported binding pattern # <- no code, no file, no line:col
On a 13 MB single-file bundle the difference is stark: check pinpoints …:551:5336; compile gives you Error: Unsupported binding pattern and nothing else to go on.
Root cause
lower_bail! (crates/perry-hir/src/error.rs:46) correctly constructs a span-tagged LowerError:
macro_rules! lower_bail {
($span:expr, $($arg:tt)*) => {
return Err(anyhow::Error::new(LowerError::new(format!($($arg)*), $span)))
};
}
…but LowerError's Display (error.rs:34) emits only the message:
impl std::fmt::Display for LowerError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message) // span is dropped
}
}
perry check downcasts to LowerError and resolves span against the source map to print file:line:col + a code. The compile error path just prints the anyhow Display chain, so the captured span is silently discarded. (The module doc-comment even notes the span exists "so downstream tooling (notably perry check) can downcast and produce a diagnostic with a proper span instead of a locationless message" — compile just doesn't do that downcast.)
Suggested fix
Have the compile error path downcast to LowerError (as check already does) and render the span — error[CODE] --> file:line:col — falling back to the bare message only when span is None. Ideally share the diagnostic renderer between check and compile so both stay consistent.
Why it matters
A locationless lowering error is fine on a 5-line test but useless on generated/minified/bundled code, which is exactly where un-handled syntactic corners surface. The span is already captured; it's purely a rendering gap on the compile side.
Environment
perry 0.5.1175, built from main @ a5d7b3e64
Summary
Lowering errors carry a source span (
LowerError { message, span: Option<Span> }), andperry checkrenders it as a propererror[CODE] --> file:line:coldiagnostic. Butperry compileprints only the bare message with no location. On large/minified/generated inputs this makes any lowering wall effectively undiagnosable — you get a one-line error with no way to find the offending construct.Repro
Same input, two front-ends:
On a 13 MB single-file bundle the difference is stark:
checkpinpoints…:551:5336;compilegives youError: Unsupported binding patternand nothing else to go on.Root cause
lower_bail!(crates/perry-hir/src/error.rs:46) correctly constructs a span-taggedLowerError:…but
LowerError'sDisplay(error.rs:34) emits only the message:perry checkdowncasts toLowerErrorand resolvesspanagainst the source map to printfile:line:col+ a code. Thecompileerror path just prints the anyhowDisplaychain, so the captured span is silently discarded. (The module doc-comment even notes the span exists "so downstream tooling (notablyperry check) can downcast and produce a diagnostic with a proper span instead of a locationless message" —compilejust doesn't do that downcast.)Suggested fix
Have the
compileerror path downcast toLowerError(ascheckalready does) and render the span —error[CODE] --> file:line:col— falling back to the bare message only whenspanisNone. Ideally share the diagnostic renderer betweencheckandcompileso both stay consistent.Why it matters
A locationless lowering error is fine on a 5-line test but useless on generated/minified/bundled code, which is exactly where un-handled syntactic corners surface. The span is already captured; it's purely a rendering gap on the
compileside.Environment
perry 0.5.1175, built frommain@a5d7b3e64