rename none to null
This commit is contained in:
@@ -93,11 +93,11 @@
|
||||
- if statements (implemented). example: `if condition { ... } else if { ... } else { ... }`
|
||||
- conditions must be `bool`; block-scoped locals do not escape their blocks
|
||||
- lowered through new `Label` / `Br` / `Cond_Br` IR opcodes (alloca-backed locals, no phi nodes)
|
||||
- conditional unwrapping for optionals (`?T`) (implemented): `if val |v| { ... } else { ... }` - unwrap `val` into `v` if it is not `none`
|
||||
- conditional unwrapping for optionals (`?T`) (implemented): `if val |v| { ... } else { ... }` - unwrap `val` into `v` if it is not `null`
|
||||
- single immutable binding scoped to the then-block; `v` not visible in `else` or after the `if`
|
||||
- `|` lexes as a new `Pipe` token; the `.If` reuses AST `name` / HIR `local` to carry the binding (no new statement kind)
|
||||
- new `Optional_Is_Some` / `Optional_Value` IR opcodes (the `Unwrap` presence-test + extract, minus the trap)
|
||||
- conditional unwrapping with guard clause (implemented): `if val |v : v >= 10| { ... } else { ... }` - enter the then-block when `val` is not `none` and the guard is true
|
||||
- conditional unwrapping with guard clause (implemented): `if val |v : v >= 10| { ... } else { ... }` - enter the then-block when `val` is not `null` and the guard is true
|
||||
- multi-unwrap (implemented; see section below)
|
||||
- while loops (implemented; operates on boolean conditions). examples:
|
||||
- `while condition { ... }` - iterate while the condition is true
|
||||
@@ -189,7 +189,7 @@
|
||||
}
|
||||
```
|
||||
- disallow: `b :: undefined` since assigning undefined to something that can't change defeats the purpose
|
||||
- disallow assigning `undefined` after declaration; use optionals and `none` for values that intentionally move back to an empty state
|
||||
- disallow assigning `undefined` after declaration; use optionals and `null` for values that intentionally move back to an empty state
|
||||
|
||||
13. introduce `float` and `range` type constraints (the `int` family generalized) (implemented)
|
||||
- `float` resolves a local binding to any float scalar (`f32`/`f64`) via static analysis;
|
||||
@@ -351,9 +351,9 @@
|
||||
`target = if …` are supported too
|
||||
- value-loop: a labeled body `for/while … blk: { … }` whose early exits are
|
||||
`yield :blk x` and whose body ends in an unlabeled fall-through `yield` (the value
|
||||
when the loop completes). The `{T, none}` yields resolve the result to `?T`
|
||||
(a pure-AST `none`-scan picks optionality; the first concrete yield fixes the element
|
||||
type). E.g. `active_ent_idx :: for 0..10 |i| blk: { if (cond) yield :blk i; yield none }`
|
||||
when the loop completes). The `{T, null}` yields resolve the result to `?T`
|
||||
(a pure-AST `null`-scan picks optionality; the first concrete yield fixes the element
|
||||
type). E.g. `active_ent_idx :: for 0..10 |i| blk: { if (cond) yield :blk i; yield null }`
|
||||
resolves to `?usize`
|
||||
- new `blk:` / `yield :blk` label surface adds one `label` field to the AST `Stmt`; no new
|
||||
token (`blk:` is `Identifier Colon`, `:blk` is `Colon Identifier`). The parser carries a
|
||||
@@ -370,7 +370,7 @@
|
||||
loop. The TODO "BAD" loops (unlabeled yield from inside an `if`, an unbound labeled loop)
|
||||
fall out of these naturally
|
||||
- follow-ups: a branch that early-`return`s instead of yielding, unwrap-`if` as a value
|
||||
source, and `none`-before-concrete typing in untyped loops are done in 20.6; labeled value
|
||||
source, and `null`-before-concrete typing in untyped loops are done in 20.6; labeled value
|
||||
blocks and `yield`/`break` to an outer loop are done in 20.7
|
||||
|
||||
20.6 value if/loop follow-ups (implemented; checker-only)
|
||||
@@ -383,16 +383,16 @@
|
||||
guard), each branch assigning the slot; the HIR `.If` carries the unwraps, which the existing
|
||||
lowering already handles. (The simple "unwrap or fallback" case is just `orelse` —
|
||||
`name :: opt orelse d` — already a plain expression.)
|
||||
- untyped value loops pre-type their element from the first concrete (non-`none`) yield
|
||||
- untyped value loops pre-type their element from the first concrete (non-`null`) yield
|
||||
regardless of source order (a capture-scoped probe build, `value_loop_element_type`), so a
|
||||
`none` yielded before any concrete value still resolves the result to `?T`
|
||||
`null` yielded before any concrete value still resolves the result to `?T`
|
||||
- still checker-only; no HIR/lowering change
|
||||
|
||||
20.7 labels — value blocks + yield/break to an outer loop (implemented; first lowering change)
|
||||
- `x :: blk: { …; yield :blk v }` — a labeled value *block* (the disambiguated form of "an
|
||||
if/loop at the end of a block"; an unlabeled trailing if/loop stays ambiguous and is not a
|
||||
value source). `yield :blk v` exits the block with a value; every path must yield. Carries
|
||||
the same `{T, none}` → `?T` typing, defer-capture, and reassignment forms as value loops
|
||||
the same `{T, null}` → `?T` typing, defer-capture, and reassignment forms as value loops
|
||||
- `yield :outer v` to an enclosing (non-innermost) value loop/block, plus plain `break :L` /
|
||||
`continue :L` to an enclosing labeled loop
|
||||
- a label now names a first-class exit target: `label` added to the HIR `Stmt` (on
|
||||
@@ -406,10 +406,10 @@
|
||||
`.Block` break target; not a loop, so unlabeled `break`/`continue` and `continue :blk` skip
|
||||
it). The checker tracks a parallel `loop_is_loop` stack so labeled `break` reaches a loop or
|
||||
block while `continue` and unlabeled `break`/`continue` reach only the innermost loop
|
||||
- untyped block `none`-before-concrete typing now builds the block's leading (yield-free)
|
||||
- untyped block `null`-before-concrete typing now builds the block's leading (yield-free)
|
||||
statements first (a throwaway probe), so a first concrete `yield :blk` that references a
|
||||
block local still resolves the result to `?T`
|
||||
- deferred (`// ponytail:`): the same `none`-before-concrete typing in an untyped block (or
|
||||
- deferred (`// ponytail:`): the same `null`-before-concrete typing in an untyped block (or
|
||||
loop) whose concrete yield references a local declared *past* the first yield (annotate)
|
||||
|
||||
21. unions and tagged unions (implemented; first pass — native untagged unions only; see below)
|
||||
@@ -947,6 +947,8 @@
|
||||
- comptime local declarations resolve type syntax in the active interpreter state, preserving match captures
|
||||
- `EnumFieldStruct` sizes its working arrays directly from the comptime `.enum |info|` capture
|
||||
|
||||
47. rename optional `none` to `null` (implemented)
|
||||
|
||||
## A word on unchecked casts
|
||||
|
||||
For casts that bypass safety checks, Honey provides builtin functions:
|
||||
@@ -978,13 +980,13 @@ ptr := ptrcast!(addr, @u8) # integer to pointer
|
||||
|
||||
## A word on multi-unwrap
|
||||
|
||||
Unwrap multiple optionals with `and`. This **short-circuits**: if the first optional is none, subsequent expressions are not evaluated.
|
||||
Unwrap multiple optionals with `and`. This **short-circuits**: if the first optional is null, subsequent expressions are not evaluated.
|
||||
|
||||
```
|
||||
name: ?[]u8 = get_name()
|
||||
age: ?u8 = get_age()
|
||||
if name and age |n, a| {
|
||||
# both n and a are guaranteed non-none here
|
||||
# both n and a are guaranteed non-null here
|
||||
print("{s} is {d} years old", n, a)
|
||||
}
|
||||
```
|
||||
@@ -1013,7 +1015,7 @@ The `and` in multi-unwrap short-circuits left-to-right:
|
||||
|
||||
```
|
||||
if get_name() and get_hat() |n, h| {
|
||||
# get_hat() is only called if get_name() returned non-none
|
||||
# get_hat() is only called if get_name() returned non-null
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1242,7 +1244,7 @@ Yielding is also possible from loops with the same constraint.
|
||||
# get active entity
|
||||
active_ent_idx :: for 0..10 |i| blk: {
|
||||
if is_active(some_entity, i) yield :blk i
|
||||
yield none # fall-through: no active ent was found (this should imply a return type matching both the index value and `none`, meaning it should resolve to an optional in this case)
|
||||
yield null # fall-through: no active ent was found (this should imply a return type matching both the index value and `null`, meaning it should resolve to an optional in this case)
|
||||
|
||||
# note that in this case, we have to use the `blk` label to yield from the correct scope.
|
||||
# otherwise, the yield should return directly from the if-statement's scope (which would be incorrect in this case).
|
||||
@@ -1251,13 +1253,13 @@ active_ent_idx :: for 0..10 |i| blk: {
|
||||
# BAD: yield returned from if-statement, but no name binds it: should miscompile similar to unused return values from functions.
|
||||
active_ent_idx :: for 0..10 |i| {
|
||||
if is_active(some_entity, i) yield i # bad
|
||||
yield none
|
||||
yield null
|
||||
}
|
||||
|
||||
# BAD: likewise for loops
|
||||
for 0..10 |i| blk: { # bad, no name binds returned value
|
||||
if is_active(some_entity, i) yield :blk i
|
||||
yield none
|
||||
yield null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user