rename none to null
This commit is contained in:
@@ -81,7 +81,7 @@ Yield_Target :: struct {
|
||||
label: symbol.Id,
|
||||
slot: hir.Local_Id,
|
||||
slot_type: types.Type,
|
||||
// True when the loop also yields `none` (a `{T, none}` set → `?T`); set from a
|
||||
// True when the loop also yields `null` (a `{T, null}` set → `?T`); set from a
|
||||
// pure-AST scan, used to pick the slot's element type on the first concrete yield.
|
||||
result_optional: bool,
|
||||
// `len(defers)` when this target's body began; a `yield :label` flushes defers down
|
||||
@@ -394,7 +394,7 @@ block_reads_name :: proc(checker: ^Checker, statements: []ast.Stmt_Id, name: sym
|
||||
case .Add, .Sub, .Mul, .Div, .Bit_And, .Bit_Or, .Bit_Xor, .Shift_Left, .Shift_Right,
|
||||
.Shift_Left_Saturating, .Index, .Orelse, .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or, .Range:
|
||||
append(&expr_stack, expr.left, expr.right)
|
||||
case .Invalid, .Integer, .Float, .String, .Bool, .None, .Undefined, .Inference_Hole,
|
||||
case .Invalid, .Integer, .Float, .String, .Bool, .Null, .Undefined, .Inference_Hole,
|
||||
.Type, .Name, .Function_Literal, .Anonymous_Struct_Type:
|
||||
}
|
||||
}
|
||||
@@ -639,9 +639,9 @@ build_static_value :: proc(checker: ^Checker, value: Ct_Value, span: source.Span
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if value.kind == .None {
|
||||
if value.kind == .Null {
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.None, span=span, type=value.type,
|
||||
kind=.Null, span=span, type=value.type,
|
||||
target=hir.INVALID_REF, left=hir.INVALID_EXPR, right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
@@ -2797,7 +2797,7 @@ infer_call_comptime_values :: proc(
|
||||
for value_bound in bound {
|
||||
all_bound = all_bound && value_bound
|
||||
}
|
||||
// Concrete arguments bind first. Numeric constants and `none` are contextual and
|
||||
// Concrete arguments bind first. Numeric constants and `null` are contextual and
|
||||
// therefore only contribute after stronger evidence has had a chance to bind the
|
||||
// parameter type.
|
||||
weak_passes := [2]bool{false, true}
|
||||
@@ -2811,8 +2811,8 @@ infer_call_comptime_values :: proc(
|
||||
continue
|
||||
}
|
||||
arg_expr := checker.ast_module.exprs[arg_id]
|
||||
is_none := arg_expr.kind == .None
|
||||
is_weak := is_numeric_constant_expr(checker, arg_id) || is_none
|
||||
is_null := arg_expr.kind == .Null
|
||||
is_weak := is_numeric_constant_expr(checker, arg_id) || is_null
|
||||
if is_weak != weak {
|
||||
continue
|
||||
}
|
||||
@@ -2836,7 +2836,7 @@ infer_call_comptime_values :: proc(
|
||||
}
|
||||
}
|
||||
actual := actual_args[param_index]
|
||||
if is_none {
|
||||
if is_null {
|
||||
previous := checker.current_comptime_values
|
||||
checker.current_comptime_values = values
|
||||
contextual := type_from_syntax(
|
||||
@@ -3506,7 +3506,7 @@ mark_expr_imports_used :: proc(checker: ^Checker, expr_id: ast.Expr_Id, file: as
|
||||
case .Add, .Sub, .Mul, .Div, .Bit_And, .Bit_Or, .Bit_Xor, .Shift_Left, .Shift_Right,
|
||||
.Shift_Left_Saturating, .Index, .Orelse, .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or, .Range:
|
||||
append(&stack, expr.left, expr.right)
|
||||
case .Invalid, .Integer, .Float, .String, .Bool, .None, .Undefined, .Inference_Hole, .Type, .Name, .Anonymous_Struct_Type:
|
||||
case .Invalid, .Integer, .Float, .String, .Bool, .Null, .Undefined, .Inference_Hole, .Type, .Name, .Anonymous_Struct_Type:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4585,10 +4585,10 @@ infer_compound_expr :: proc(
|
||||
case .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or:
|
||||
left_expr := checker.ast_module.exprs[expr.left]
|
||||
right_expr := checker.ast_module.exprs[expr.right]
|
||||
if left_expr.kind == .None && right_expr.kind != .None {
|
||||
if left_expr.kind == .Null && right_expr.kind != .Null {
|
||||
right := infer_nested_expr(checker, expr.right, locals, pkg, file, demanded, local_types)
|
||||
_ = infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types, right)
|
||||
} else if right_expr.kind == .None && left_expr.kind != .None {
|
||||
} else if right_expr.kind == .Null && left_expr.kind != .Null {
|
||||
left := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
|
||||
_ = infer_nested_expr(checker, expr.right, locals, pkg, file, demanded, local_types, left)
|
||||
} else {
|
||||
@@ -4629,7 +4629,7 @@ infer_compound_expr :: proc(
|
||||
element = types.I64
|
||||
}
|
||||
return types.array(store, element, u64(len(expr.args)), false)
|
||||
case .None:
|
||||
case .Null:
|
||||
return expected if types.is_optional(expected, store) else types.INVALID
|
||||
case .Undefined:
|
||||
return types.INVALID
|
||||
@@ -4928,7 +4928,7 @@ infer_expr :: proc(
|
||||
case .Float:
|
||||
last = types.F64
|
||||
_ = pop(&stack)
|
||||
case .String, .Array, .None, .Undefined, .Address, .Deref, .Index, .Slice,
|
||||
case .String, .Array, .Null, .Undefined, .Address, .Deref, .Index, .Slice,
|
||||
.Field, .Unwrap, .Orelse, .Try, .Catch, .Struct_Literal, .Keyed, .Enum_Literal, .Cast,
|
||||
.Comptime, .Bool, .Not, .Bit_Not, .Bit_And, .Bit_Or, .Bit_Xor, .Shift_Left,
|
||||
.Shift_Right, .Shift_Left_Saturating, .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or, .Range:
|
||||
@@ -7773,13 +7773,13 @@ build_compound_expr :: proc(
|
||||
target=hir.INVALID_REF, left=hir.INVALID_EXPR, right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .None:
|
||||
case .Null:
|
||||
if !types.is_optional(expected, store) {
|
||||
id := source.add(checker.diagnostics, expr.span, "'none' requires an optional context")
|
||||
id := source.add(checker.diagnostics, expr.span, "'null' requires an optional context")
|
||||
return invalid_hir_expr(checker, expr.span, id, expected)
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.None, span=expr.span, type=expected, target=hir.INVALID_REF,
|
||||
kind=.Null, span=expr.span, type=expected, target=hir.INVALID_REF,
|
||||
left=hir.INVALID_EXPR, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Undefined:
|
||||
@@ -8311,7 +8311,7 @@ build_compound_expr :: proc(
|
||||
case .Eq, .Ne, .Lt, .Le, .Gt, .Ge:
|
||||
// Contextualize literals whose type comes from their peer. This covers
|
||||
// integer and enum literals as well as optional presence tests such as
|
||||
// `value == none` and `none != value`.
|
||||
// `value == null` and `null != value`.
|
||||
left_const := eval_constant(checker, expr.left)
|
||||
right_const := eval_constant(checker, expr.right)
|
||||
left, right: hir.Expr_Id
|
||||
@@ -8319,10 +8319,10 @@ build_compound_expr :: proc(
|
||||
right_expr := checker.ast_module.exprs[expr.right]
|
||||
left_numeric_const := left_const.kind == .Value || is_float_constant_expr(checker, expr.left)
|
||||
right_numeric_const := right_const.kind == .Value || is_float_constant_expr(checker, expr.right)
|
||||
if right_expr.kind == .None && left_expr.kind != .None {
|
||||
if right_expr.kind == .Null && left_expr.kind != .Null {
|
||||
left = build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
|
||||
right = build_nested_expr(checker, expr.right, locals, global_reads, calls, checker.module.exprs[left].type, pkg, file)
|
||||
} else if left_expr.kind == .None && right_expr.kind != .None {
|
||||
} else if left_expr.kind == .Null && right_expr.kind != .Null {
|
||||
right = build_nested_expr(checker, expr.right, locals, global_reads, calls, types.INVALID, pkg, file)
|
||||
left = build_nested_expr(checker, expr.left, locals, global_reads, calls, checker.module.exprs[right].type, pkg, file)
|
||||
} else if right_expr.kind == .Enum_Literal && left_expr.kind != .Enum_Literal {
|
||||
@@ -8349,10 +8349,10 @@ build_compound_expr :: proc(
|
||||
left_type := checker.module.exprs[left].type
|
||||
right_type := checker.module.exprs[right].type
|
||||
operand_type := types.INVALID
|
||||
if left_expr.kind == .None || right_expr.kind == .None {
|
||||
if left_expr.kind == .Null || right_expr.kind == .Null {
|
||||
if expr.kind != .Eq && expr.kind != .Ne ||
|
||||
!types.is_optional(left_type, store) || !types.equal(left_type, right_type) {
|
||||
id := source.add(checker.diagnostics, expr.span, "'none' only supports '==' and '!=' with an optional value")
|
||||
id := source.add(checker.diagnostics, expr.span, "'null' only supports '==' and '!=' with an optional value")
|
||||
return invalid_hir_expr(checker, expr.span, id, types.BOOL)
|
||||
}
|
||||
operand_type = left_type
|
||||
@@ -8703,7 +8703,7 @@ build_expr :: proc(
|
||||
continue
|
||||
}
|
||||
switch expr.kind {
|
||||
case .String, .Array, .None, .Undefined, .Address, .Deref, .Index, .Slice,
|
||||
case .String, .Array, .Null, .Undefined, .Address, .Deref, .Index, .Slice,
|
||||
.Field, .Unwrap, .Orelse, .Try, .Catch, .Struct_Literal, .Keyed,
|
||||
.Bool, .Cast, .Comptime, .Not, .Bit_Not, .Bit_And, .Bit_Or, .Bit_Xor, .Shift_Left,
|
||||
.Shift_Right, .Shift_Left_Saturating, .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or, .Range,
|
||||
@@ -12567,24 +12567,24 @@ build_value_match :: proc(
|
||||
return slot_read(checker, slot, slot_type, span), slot_type
|
||||
}
|
||||
|
||||
// loop_yields_none reports whether any `yield` that targets this loop (a labeled
|
||||
// loop_yields_null reports whether any `yield` that targets this loop (a labeled
|
||||
// `yield :blk` inside `if`/block branches, or the trailing fall-through) yields the
|
||||
// literal `none` — making the loop's result optional. Pure AST walk; does not descend
|
||||
// literal `null` — making the loop's result optional. Pure AST walk; does not descend
|
||||
// into nested loops or value sources, whose yields belong to them.
|
||||
loop_yields_none :: proc(checker: ^Checker, stmts: []ast.Stmt_Id) -> bool {
|
||||
loop_yields_null :: proc(checker: ^Checker, stmts: []ast.Stmt_Id) -> bool {
|
||||
for id in stmts {
|
||||
s := checker.ast_module.statements[id]
|
||||
#partial switch s.kind {
|
||||
case .Yield:
|
||||
if s.expr != ast.INVALID_EXPR && checker.ast_module.exprs[s.expr].kind == .None {
|
||||
if s.expr != ast.INVALID_EXPR && checker.ast_module.exprs[s.expr].kind == .Null {
|
||||
return true
|
||||
}
|
||||
case .If:
|
||||
if loop_yields_none(checker, s.body) || loop_yields_none(checker, s.else_body) {
|
||||
if loop_yields_null(checker, s.body) || loop_yields_null(checker, s.else_body) {
|
||||
return true
|
||||
}
|
||||
case .Block:
|
||||
if loop_yields_none(checker, s.body) {
|
||||
if loop_yields_null(checker, s.body) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -12593,8 +12593,8 @@ loop_yields_none :: proc(checker: ^Checker, stmts: []ast.Stmt_Id) -> bool {
|
||||
}
|
||||
|
||||
// resolve_loop_slot fixes a value-loop's result slot from its first concrete yield (an
|
||||
// optional element type when the loop also yields `none`) and coerces `value` into it.
|
||||
// Returns INVALID when the type can't be fixed yet (a `none`/invalid first yield).
|
||||
// optional element type when the loop also yields `null`) and coerces `value` into it.
|
||||
// Returns INVALID when the type can't be fixed yet (a `null`/invalid first yield).
|
||||
resolve_loop_slot :: proc(ctx: ^Build_Ctx, target: ^Yield_Target, value: hir.Expr_Id, vtype: types.Type, span: source.Span) -> hir.Expr_Id {
|
||||
checker := ctx.checker
|
||||
if target.slot == hir.INVALID_LOCAL {
|
||||
@@ -12608,14 +12608,14 @@ resolve_loop_slot :: proc(ctx: ^Build_Ctx, target: ^Yield_Target, value: hir.Exp
|
||||
}
|
||||
|
||||
// first_concrete_yield_expr returns the AST expr of the first yield (source order) that is
|
||||
// not the literal `none`, descending into `if`/block branches but not nested loops or value
|
||||
// sources (whose yields belong to them). INVALID when the loop yields only `none`.
|
||||
// not the literal `null`, descending into `if`/block branches but not nested loops or value
|
||||
// sources (whose yields belong to them). INVALID when the loop yields only `null`.
|
||||
first_concrete_yield_expr :: proc(checker: ^Checker, stmts: []ast.Stmt_Id) -> ast.Expr_Id {
|
||||
for id in stmts {
|
||||
s := checker.ast_module.statements[id]
|
||||
#partial switch s.kind {
|
||||
case .Yield:
|
||||
if s.expr != ast.INVALID_EXPR && checker.ast_module.exprs[s.expr].kind != .None {
|
||||
if s.expr != ast.INVALID_EXPR && checker.ast_module.exprs[s.expr].kind != .Null {
|
||||
return s.expr
|
||||
}
|
||||
case .If:
|
||||
@@ -12635,9 +12635,9 @@ first_concrete_yield_expr :: proc(checker: ^Checker, stmts: []ast.Stmt_Id) -> as
|
||||
}
|
||||
|
||||
// value_loop_element_type pre-types the element of an untyped value loop from its first
|
||||
// concrete (non-`none`) yield, so a `none` yielded before any concrete value still resolves
|
||||
// concrete (non-`null`) yield, so a `null` yielded before any concrete value still resolves
|
||||
// the result to `?T`. The loop's captures are bound temporarily for the probe and the probe
|
||||
// expr is discarded; returns INVALID when the loop yields only `none`.
|
||||
// expr is discarded; returns INVALID when the loop yields only `null`.
|
||||
value_loop_element_type :: proc(ctx: ^Build_Ctx, loop_stmt: ast.Stmt) -> types.Type {
|
||||
checker := ctx.checker
|
||||
yield_expr := first_concrete_yield_expr(checker, loop_stmt.body)
|
||||
@@ -12736,7 +12736,7 @@ block_element_type :: proc(ctx: ^Build_Ctx, block_stmts: []ast.Stmt_Id) -> types
|
||||
// reads it after the block. Every path must yield (or otherwise exit); HIR holds a `.Block`
|
||||
// that emits the body and the exit label the labeled breaks branch to. No iteration / no
|
||||
// fall-through (unlike a value loop). The type is the annotation when typed, else the first
|
||||
// concrete `yield :blk`'s type (optional when any yield is `none`).
|
||||
// concrete `yield :blk`'s type (optional when any yield is `null`).
|
||||
build_value_labeled_block :: proc(
|
||||
ctx: ^Build_Ctx,
|
||||
body: ^[dynamic]hir.Stmt_Id,
|
||||
@@ -12746,7 +12746,7 @@ build_value_labeled_block :: proc(
|
||||
span: source.Span,
|
||||
) -> (value: hir.Expr_Id, value_type: types.Type) {
|
||||
checker := ctx.checker
|
||||
result_optional := loop_yields_none(checker, block_stmts)
|
||||
result_optional := loop_yields_null(checker, block_stmts)
|
||||
slot := hir.INVALID_LOCAL
|
||||
slot_type := types.INVALID
|
||||
if is_runtime_type(checker, expected) {
|
||||
@@ -12754,8 +12754,8 @@ build_value_labeled_block :: proc(
|
||||
slot = new_value_slot(ctx, slot_type)
|
||||
result_optional = types.is_optional(slot_type, &checker.module.types)
|
||||
} else if result_optional {
|
||||
// Untyped block that also yields `none`: pre-type the element from the first
|
||||
// concrete yield (regardless of source order) so a `none` yielded first still
|
||||
// Untyped block that also yields `null`: pre-type the element from the first
|
||||
// concrete yield (regardless of source order) so a `null` yielded first still
|
||||
// resolves the result to `?T`.
|
||||
elem := block_element_type(ctx, block_stmts)
|
||||
if is_runtime_type(checker, elem) {
|
||||
@@ -12816,7 +12816,7 @@ build_value_labeled_block :: proc(
|
||||
// desugars (in build_block) to `slot = x; break`, and the construct's value is a read
|
||||
// of the slot after the loop. Reuses the ordinary `.For`/`.While` build via a peeled
|
||||
// copy; no new HIR. The yielded type is the annotation when typed, else the first
|
||||
// concrete yield's type (optional when any yield is `none`).
|
||||
// concrete yield's type (optional when any yield is `null`).
|
||||
build_value_loop :: proc(
|
||||
ctx: ^Build_Ctx,
|
||||
body: ^[dynamic]hir.Stmt_Id,
|
||||
@@ -12844,7 +12844,7 @@ build_value_loop :: proc(
|
||||
}
|
||||
fall_stmt := checker.ast_module.statements[loop_stmt.body[n - 1]]
|
||||
|
||||
result_optional := loop_yields_none(checker, loop_stmt.body)
|
||||
result_optional := loop_yields_null(checker, loop_stmt.body)
|
||||
slot := hir.INVALID_LOCAL
|
||||
slot_type := types.INVALID
|
||||
if is_runtime_type(checker, expected) {
|
||||
@@ -12852,8 +12852,8 @@ build_value_loop :: proc(
|
||||
slot = new_value_slot(ctx, slot_type)
|
||||
result_optional = types.is_optional(slot_type, &checker.module.types)
|
||||
} else if result_optional {
|
||||
// Untyped loop that also yields `none`: pre-type the element from the first
|
||||
// concrete yield (regardless of source order) so a `none` built before any
|
||||
// Untyped loop that also yields `null`: pre-type the element from the first
|
||||
// concrete yield (regardless of source order) so a `null` built before any
|
||||
// concrete yield still resolves the result to `?T`.
|
||||
elem := value_loop_element_type(ctx, loop_stmt)
|
||||
if is_runtime_type(checker, elem) {
|
||||
|
||||
Reference in New Issue
Block a user