Skip to content

Proposal: improved semantics for noreturn-like types #15909

Open
@mlugg

Description

@mlugg

This is in a sense a continuation of #3257. That issue laid some of the groundwork for the current status of noreturn and similar types, but there are a few things missing. Also, thanks to @ifreund for helping me figure out some of the details of this.

Lots of types can be constructed which are similar to noreturn. In type theory terms, they are "empty types": types for which no values exist. I'll call these types "noreturn-like". Here's an exhaustive list of types which should be considered noreturn-like (note the special cases around pointers mentioned at the end):

  • noreturn
  • enum {}
  • enum(T) {} for any T
  • error {}
  • union / extern union where all fields are noreturn-like (including the case where the union has no fields)
  • tagged unions where the tag type is noreturn-like or all fields are noreturn-like
  • structs containing any noreturn-like field
  • E!T where E and T are both noreturn-like (so, error{}!T)
  • [n]T / @Vector(n, T) where T is noreturn-like and n != 0
  • *T / [*]T (and any qualifiers) where T is noreturn-like
    • []T has the value &.{} so is not noreturn-like, but rather zero-bit OPV
    • [*c]T has the value null so is not noreturn-like. In principle it's zero-bit OPV, but this is a footgun, so instead is disallowed.

Currently, most of these aren't "truly" considered noreturn-like. Such types should terminate semantic analysis when found (akin to unreachable). Additionally, undefined should not coerce to noreturn-like types, to avoid being able to actually "construct" them without terminating analysis.

We currently have the restriction that (at function scope) var x: T = ..., where T is noreturn-like, is a compile error. This, however, is inconsistent - const x: T = ... is allowed, and moreover, so is var x = @as(T, ...). I propose that we remove this needless restriction. Allocs for noreturn-like types can be special-cased to emit no AIR instructions, and analysis will terminate before we attempt to store to one, as by that point we will have had an instruction whose result type is the child type.

Note, however, that global vars may not be of a noreturn-like type, nor may a value of a noreturn-like type be exported or marked extern. This is a compile error.

One last notable change in semantics here is that switching on a noreturn-like enum is no longer supported in the same way that it is in status quo. The idea currently is that you turn such an enum into the true noreturn type using an empty switch, switch (e) {}. This code will still be accepted under this proposal, but for a different reason: it's never analyzed! The moment e is created, semantic analysis terminates, since we reached a noreturn instruction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions