Skip to content

bug - assert false lowers to unit in non-None return contexts #644

@dannymeijer

Description

@dannymeijer

Thanks for reporting! Please include a minimal reproduction when possible.

Area

  • Incan Language (syntax/semantics)
  • Compiler (frontend/backend/codegen)

Summary

Expected: assert false, message is a guaranteed failing control-flow path. A function whose body always fails through assert false should typecheck for any declared return type, the same way a typed failure helper can be used to produce an arbitrary T in unreachable paths.

Actual: assert false lowers to a Rust if !(false) { ... } expression with unit type. In a function returning a non-None type, generated Rust fails with E0317: if may be missing an else clause. This makes a direct Incan failure helper impossible without routing through std.testing.fail_t or returning a dummy value after the assertion.

This surfaced while replacing a host-language metadata validator in InQL PR #42 with an Incan script. The current workaround is sound but awkward: the script imports std.testing.fail_t only to express a typed failure path.

Reproduction steps

Minimal non-generic repro:

incan run -c 'def fail_int(message: str) -> int:
    assert false, message


def main() -> None:
    _ = fail_int("boom")'

Motivating generic helper repro:

incan run -c 'def fail_as[T](message: str) -> T:
    assert false, message


def main() -> None:
    _ = fail_as[int]("boom")'

Duplicate searches performed before filing:

gh issue list --repo dannys-code-corner/incan --state open --search "assert false generic return type bottom expected T found ()"
gh issue list --repo dannys-code-corner/incan --state open --search "assert false non-None return E0317"
gh issue list --repo dannys-code-corner/incan --state all --search "assert false expected i64 found unit"
gh issue list --repo dannys-code-corner/incan --state all --search "bottom type Never assert"

No matching issue was found.

Output / logs

For the non-generic repro, generated Rust compilation fails with:

error[E0317]: `if` may be missing an `else` clause
  --> src/main.rs:7:5
   |
 6 |   fn fail_int(message: String) -> i64 {
   |                                   --- expected `i64` because of this return type
 7 | /     if !(false) {
 8 | |         {
 9 | |             let __incan_assert_msg = message;
10 | |             if __incan_assert_msg.is_empty() {
...  |
16 | |     }
   | |_____^ expected `i64`, found `()`
   |
   = note: `if` expressions without `else` evaluate to `()`

For the generic repro, the same lowering fails against the type parameter:

error[E0317]: `if` may be missing an `else` clause
  --> src/main.rs:7:5
   |
 6 |   fn fail_as<T>(message: String) -> T {
   |              -                      - expected `T` because of this return type
   |              |
   |              expected this type parameter
 7 | /     if !(false) {
...
16 | |     }
   | |_____^ expected type parameter `T`, found `()`

Environment

OS: macOS
Rust: local Incan release branch toolchain
Incan: incan 0.3.0-rc10, release/v0.3
Command: incan run -c <repro>
Context: discovered while replacing the InQL RFC 014 metadata checker with an Incan script in InQL PR #42.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingincan compilerSuggestions, features, or bugs related to the Compiler (frontend/backend/codegen)incan language semanticsSuggestions, features, or bugs related to the Incan Language itself (syntax and semantics)

Type

No fields configured for Bug.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions