Skip to content

fix(ILO-468): type-check braceless-guard tail value against declared return#772

Merged
danieljohnmorris merged 3 commits into
mainfrom
ilo-468-guard-tail-type-check
May 23, 2026
Merged

fix(ILO-468): type-check braceless-guard tail value against declared return#772
danieljohnmorris merged 3 commits into
mainfrom
ilo-468-guard-tail-type-check

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

A braceless guard cond expr early-returns expr, but the verifier only checked the function body's last statement against the declared return type. When a guard's tail value had the wrong type and was followed by a type-correct fallback, the mismatch slipped through silently.

The repro that motivated this:

pred q:t>b;=q "" 1;false

At runtime pred "" returned the number 1. Passing pred to flt produced an empty result with zero warnings — flt got non-bool predicates and silently filtered everything out.

Fix

In verify_stmt for Stmt::Guard { braceless: true, .. }, compare the guard body's value type against the enclosing function's declared return type (via self.functions[func].return_type) and emit ILO-T008 on mismatch. The inline-lambda case (synthetic __lit_N function) is covered by the same code path.

No implicit coercion. Surfaces the mismatch as an error at the guard tail's span.

Changes

  • src/verify.rs: new check at the Stmt::Guard arm; 5 new regression tests.
  • SPEC.md: row in cross-language gotchas table.
  • ai.txt: regenerated from SPEC by build.rs.

Test plan

  • cargo test --features cranelift,http,golden --lib passes (3510 tests, 0 failures).
  • New tests ilo468_braceless_guard_tail_wrong_type_named_fn and _inline_lambda fire ILO-T008.
  • New tests ilo468_braceless_guard_tail_matching_type_ok, _negated_matching_type_ok, _number_return_ok verify cleanly.
  • Manual ilo check on the repro confirms a clear diagnostic at the guard tail.

Closes ILO-468

🤖 Generated with Claude Code

@codecov
Copy link
Copy Markdown

codecov Bot commented May 23, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1684 1 1683 0
View the top 1 failed test(s) by shortest run time
ilo::verify::tests::ilo468_braceless_guard_tail_wrong_type_inline_lambda
Stack Traces | 0.011s run time
thread 'verify::tests::ilo468_braceless_guard_tail_wrong_type_inline_lambda' (37109) panicked at src/verify.rs:7620:9:
parse failed: [ParseError { code: "ILO-P023", position: 20, span: Span { start: 30, end: 31 }, message: "braceless guard inside a lambda body", hint: Some("braceless guards early-return from the enclosing function, not the lambda. Use the prefix ternary `?cond then else` when both arms are values, or a full braced match `?cond{then}{else}` when arms need statements.") }]
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@danieljohnmorris danieljohnmorris force-pushed the ilo-468-guard-tail-type-check branch from fbf5012 to ed6fa34 Compare May 23, 2026 21:43
Daniel Morris and others added 3 commits May 23, 2026 22:49
…return

A braceless guard `cond expr` early-returns `expr`, but the verifier
only checked the function body's last statement against the declared
return type. When a guard's tail value had the wrong type and was
followed by a type-correct fallback (`pred q:t>b;=q "" 1;false`), the
mismatch slipped through silently — at runtime the guard returned the
literal `1` (number) where `b` (bool) was expected, and downstream HOFs
like `flt` got non-bool predicates and silently produced empty results.

Fix: in `verify_stmt` for `Stmt::Guard { braceless: true, .. }`, compare
the guard body's value type against the enclosing function's declared
return type and emit ILO-T008 on mismatch. The inline-lambda case
(synthetic `__lit_N` function) is covered by the same path.

Adds five regression tests and a row in the SPEC cross-language
gotchas table.

Closes ILO-468

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@danieljohnmorris danieljohnmorris force-pushed the ilo-468-guard-tail-type-check branch from ed6fa34 to 46de634 Compare May 23, 2026 21:50
@danieljohnmorris danieljohnmorris merged commit 8d64888 into main May 23, 2026
7 of 11 checks passed
@danieljohnmorris danieljohnmorris deleted the ilo-468-guard-tail-type-check branch May 23, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant