usize indexing only

This commit is contained in:
2026-08-11 20:12:12 +02:00
parent fa53ca2219
commit c2343b54bb
8 changed files with 216 additions and 53 deletions
+4 -3
View File
@@ -63,8 +63,9 @@ nominal result type: checked integer `+`, `-`, `*`, unary `-`, bitwise operators
comparisons, and compound assignments; float arithmetic, unary `-`, comparisons, and compound comparisons, and compound assignments; float arithmetic, unary `-`, comparisons, and compound
assignments; and boolean equality/inequality. Integer literals and float literals are contextual. assignments; and boolean equality/inequality. Integer literals and float literals are contextual.
Typed backing values and separate distinct identities remain incompatible in ordinary operations; Typed backing values and separate distinct identities remain incompatible in ordinary operations;
an explicit constructor is required to cross that boundary. Distinct integers also work as indices and slice bounds; an explicit constructor is required to cross that boundary. Distinct integers require an explicit
`minval!` / `maxval!` return the distinct type. Runtime and comptime behavior match. `usize` cast for indices and slice bounds; `minval!` / `maxval!` return the distinct type.
Runtime and comptime behavior match.
`typeinfo!(Distinct).backing` reports the immediate declared backing. Standard formatting peels `typeinfo!(Distinct).backing` reports the immediate declared backing. Standard formatting peels
distinct layers recursively, so all scalar format verbs behave like the final scalar backing. distinct layers recursively, so all scalar format verbs behave like the final scalar backing.
@@ -117,7 +118,7 @@ fields. `_` is not a keyword member name.
- checked integer `+ - *`, unary `-`, float-only `/`, IEEE float arithmetic, comparisons, `!`, `and`, and `or` - checked integer `+ - *`, unary `-`, float-only `/`, IEEE float arithmetic, comparisons, `!`, `and`, and `or`
- Zig-style integer bitwise complement `~`, binary `&`, `|`, `xor`, shifts `<<` / `>>`, and saturating left shift `<<|`; postfix `^` remains pointer dereference - Zig-style integer bitwise complement `~`, binary `&`, `|`, `xor`, shifts `<<` / `>>`, and saturating left shift `<<|`; postfix `^` remains pointer dereference
- assignments and compound assignments `+= -= *= /= &= |= xor= <<= >>= <<|=` with single evaluation of complex lvalues; `/=` is float-only and `xor=` is contiguous - assignments and compound assignments `+= -= *= /= &= |= xor= <<= >>= <<|=` with single evaluation of complex lvalues; `/=` is float-only and `xor=` is contiguous
- field access through struct values and pointers, index/slice bounds contextually coerced to `usize`, and unsigned narrower index support - field access through struct values and pointers, exact `usize` indices and slice bounds, and contextual integer constants in those positions
- boolean `if` / `else if` / `else` and `for` loops with braceless single-statement bodies when the preceding expression is parenthesized or a function call - boolean `if` / `else if` / `else` and `for` loops with braceless single-statement bodies when the preceding expression is parenthesized or a function call
- `while` loops with conditional unwrap captures and guards plus optional post-iteration update clauses - `while` loops with conditional unwrap captures and guards plus optional post-iteration update clauses
- `for` loops over ranges, arrays, slices, and pointers-to-arrays with copy captures, pointer captures `|@item|`, and optional `usize` index captures; `inline for` specializes a comptime aggregate into one checked body per element - `for` loops over ranges, arrays, slices, and pointers-to-arrays with copy captures, pointer captures `|@item|`, and optional `usize` index captures; `inline for` specializes a comptime aggregate into one checked body per element
+1 -1
View File
@@ -234,7 +234,7 @@ Current prototype features:
- Pointer-preserving `.ptr`/`.len`, pointer-to-array indexing and slicing, postfix pointer dereference and optional unwrap, and keyed struct literals - Pointer-preserving `.ptr`/`.len`, pointer-to-array indexing and slicing, postfix pointer dereference and optional unwrap, and keyed struct literals
- Contextual integer constants and typed compile-time evaluation of arithmetic and Zig-style bitwise expressions - Contextual integer constants and typed compile-time evaluation of arithmetic and Zig-style bitwise expressions
- Integer `~`, `&`, `|`, `xor`, guarded `<<` / `>>`, saturating `<<|`, and their compound assignments; postfix `^` remains pointer dereference - Integer `~`, `&`, `|`, `xor`, guarded `<<` / `>>`, saturating `<<|`, and their compound assignments; postfix `^` remains pointer dereference
- Scalar-backed nominal `distinct` types with same-identity runtime/comptime operators, explicit backing extraction casts, integer bounds/indexing, reflection, and recursive standard formatting - Scalar-backed nominal `distinct` types with same-identity runtime/comptime operators, explicit backing extraction casts, integer bounds, reflection, and recursive standard formatting
- Directory packages with merged declarations and file-local relative imports - Directory packages with merged declarations and file-local relative imports
- Relative C header imports as synthetic package namespaces - Relative C header imports as synthetic package namespaces
- Plain imported C structs/unions, fixed arrays, and C function pointer typedefs, including keyed literals, field access, callbacks, and Apple Silicon by-value ABI lowering - Plain imported C structs/unions, fixed arrays, and C function pointer typedefs, including keyed literals, field access, callbacks, and Apple Silicon by-value ABI lowering
+34 -28
View File
@@ -5108,7 +5108,8 @@ infer_compound_expr :: proc(
return types.child_type(value, store) if types.is_pointer(value, store) else types.INVALID return types.child_type(value, store) if types.is_pointer(value, store) else types.INVALID
case .Index: case .Index:
value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types) value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
_ = infer_nested_expr(checker, expr.right, locals, pkg, file, demanded, local_types) _ = infer_nested_expr(checker, expr.right, locals, pkg, file, demanded, local_types, types.USIZE)
_ = record_demand(checker, expr.right, types.USIZE, locals, local_types, pkg, file)
item, ok := types.container(value, store) item, ok := types.container(value, store)
return item.child if ok else types.INVALID return item.child if ok else types.INVALID
case .Slice: case .Slice:
@@ -5124,7 +5125,8 @@ infer_compound_expr :: proc(
} }
for bound in expr.args { for bound in expr.args {
if bound != ast.INVALID_EXPR { if bound != ast.INVALID_EXPR {
_ = infer_nested_expr(checker, bound, locals, pkg, file, demanded, local_types) _ = infer_nested_expr(checker, bound, locals, pkg, file, demanded, local_types, types.USIZE)
_ = record_demand(checker, bound, types.USIZE, locals, local_types, pkg, file)
} }
} }
preserve := item.has_sentinel && expr.args[1] == ast.INVALID_EXPR preserve := item.has_sentinel && expr.args[1] == ast.INVALID_EXPR
@@ -8100,36 +8102,35 @@ build_scalar_cast :: proc(
diagnostic=source.INVALID_DIAGNOSTIC, diagnostic=source.INVALID_DIAGNOSTIC,
}) })
} }
normalize_index_expr :: proc(checker: ^Checker, value: hir.Expr_Id, span: source.Span) -> hir.Expr_Id { normalize_index_expr :: proc(
store := &checker.module.types checker: ^Checker,
current := value value: hir.Expr_Id,
current_type := checker.module.exprs[current].type span: source.Span,
representation, distinct_ok := types.distinct_scalar_backing(current_type, store) label: string,
if distinct_ok && types.is_concrete_integer(representation) { ) -> hir.Expr_Id {
for { if value == hir.INVALID_EXPR {
backing, ok := types.distinct_backing(current_type, store) return value
if !ok {
break
} }
current = add_hir_expr(checker, hir.Expr{ if _, invalid := invalid_expr_diagnostic(checker, value); invalid {
kind=.Retype, return value
span=span,
type=backing,
left=current,
target=hir.INVALID_REF,
right=hir.INVALID_EXPR,
diagnostic=source.INVALID_DIAGNOSTIC,
})
current_type = backing
} }
} current_expr := &checker.module.exprs[value]
current_expr := &checker.module.exprs[current]
if current_expr.kind == .Integer && if current_expr.kind == .Integer &&
fits_integer_type(i128(current_expr.integer), types.USIZE, checker.target) { fits_integer_type(i128(current_expr.integer), types.USIZE, checker.target) {
current_expr.type = types.USIZE current_expr.type = types.USIZE
return current return value
} }
return coerce_expr(checker, current, types.USIZE, span) if !types.equal(current_expr.type, types.USIZE) {
id := source.addf(
checker.diagnostics,
span,
"%s must have type usize, got %s",
label,
type_label(checker, current_expr.type),
)
return invalid_hir_expr(checker, span, id, types.USIZE)
}
return value
} }
@@ -8690,7 +8691,7 @@ build_compound_expr :: proc(
case .Index: case .Index:
container := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file) container := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
index := build_nested_expr(checker, expr.right, locals, global_reads, calls, types.INVALID, pkg, file) index := build_nested_expr(checker, expr.right, locals, global_reads, calls, types.INVALID, pkg, file)
index = normalize_index_expr(checker, index, expr.span) index = normalize_index_expr(checker, index, expr.span, "index")
if invalid, propagated := propagate_invalid_expr(checker, expr.span, container, index); propagated { if invalid, propagated := propagate_invalid_expr(checker, expr.span, container, index); propagated {
return invalid return invalid
} }
@@ -8734,7 +8735,12 @@ build_compound_expr :: proc(
for bound, index in expr.args { for bound, index in expr.args {
if bound != ast.INVALID_EXPR { if bound != ast.INVALID_EXPR {
bounds[index] = build_nested_expr(checker, bound, locals, global_reads, calls, types.INVALID, pkg, file) bounds[index] = build_nested_expr(checker, bound, locals, global_reads, calls, types.INVALID, pkg, file)
bounds[index] = normalize_index_expr(checker, bounds[index], checker.ast_module.exprs[bound].span) bounds[index] = normalize_index_expr(
checker,
bounds[index],
checker.ast_module.exprs[bound].span,
"slice bound",
)
if invalid, propagated := propagate_invalid_expr(checker, expr.span, bounds[index]); propagated { if invalid, propagated := propagate_invalid_expr(checker, expr.span, bounds[index]); propagated {
delete(bounds, checker.allocator) delete(bounds, checker.allocator)
return invalid return invalid
+85 -15
View File
@@ -291,6 +291,7 @@ Ct_Binding :: struct {
value: Ct_Value_Id, value: Ct_Value_Id,
cell: Ct_Cell_Id, cell: Ct_Cell_Id,
mutable: bool, mutable: bool,
open_integer: bool,
} }
Ct_Error_Refinement :: struct { Ct_Error_Refinement :: struct {
@@ -473,9 +474,23 @@ ct_extend_place :: proc(
return ct_add_place(state, base.cell, value_type, writable, extended[:]) return ct_add_place(state, base.cell, value_type, writable, extended[:])
} }
ct_bind_value :: proc(state: ^Ct_State, name: symbol.Id, value_type: types.Type, value: Ct_Value_Id, mutable: bool) { ct_bind_value :: proc(
state: ^Ct_State,
name: symbol.Id,
value_type: types.Type,
value: Ct_Value_Id,
mutable: bool,
open_integer := false,
) {
cell := ct_add_cell(state, value, mutable) cell := ct_add_cell(state, value, mutable)
append(&state.bindings, Ct_Binding{name=name, type=value_type, value=value, cell=cell, mutable=mutable}) append(&state.bindings, Ct_Binding{
name=name,
type=value_type,
value=value,
cell=cell,
mutable=mutable,
open_integer=open_integer,
})
} }
ct_pop_bindings :: proc(state: ^Ct_State, start: int) { ct_pop_bindings :: proc(state: ^Ct_State, start: int) {
@@ -581,6 +596,32 @@ ct_binding_value :: proc(state: ^Ct_State, index: int) -> Ct_Value_Id {
return binding.value return binding.value
} }
ct_contextualize_open_integer_binding :: proc(state: ^Ct_State, index: int, expected: types.Type) {
if expected != types.USIZE || index < 0 || index >= len(state.bindings) ||
!state.bindings[index].open_integer {
return
}
value_id := ct_binding_value(state, index)
if value_id == INVALID_CT_VALUE || int(value_id) >= len(state.values) {
return
}
value := state.values[value_id]
if value.kind != .Integer ||
!fits_integer_type(value.integer, expected, state.checker.target) {
return
}
value.type = expected
contextual := ct_add_value(state, value)
binding := &state.bindings[index]
binding.type = expected
binding.value = contextual
binding.open_integer = false
if binding.cell != INVALID_CT_CELL && int(binding.cell) < len(state.cells) &&
state.cells[binding.cell].live {
state.cells[binding.cell].value = contextual
}
}
ct_binding_place :: proc(state: ^Ct_State, index: int) -> Ct_Place_Id { ct_binding_place :: proc(state: ^Ct_State, index: int) -> Ct_Place_Id {
if index < 0 || index >= len(state.bindings) { if index < 0 || index >= len(state.bindings) {
return INVALID_CT_PLACE return INVALID_CT_PLACE
@@ -1315,6 +1356,7 @@ ct_eval_expr :: proc(
case .Name: case .Name:
if !symbol.is_valid(expr.qualifier) { if !symbol.is_valid(expr.qualifier) {
if index, ok := ct_find_binding_index(state, expr.name); ok { if index, ok := ct_find_binding_index(state, expr.name); ok {
ct_contextualize_open_integer_binding(state, index, expected)
return ct_observe_value(state, ct_binding_value(state, index), expr.span) return ct_observe_value(state, ct_binding_value(state, index), expr.span)
} }
if value, ok := current_comptime_value(checker, expr.name); ok { if value, ok := current_comptime_value(checker, expr.name); ok {
@@ -1452,16 +1494,19 @@ ct_eval_expr :: proc(
} }
return ct_eval_field_value(state, base_id, expr.name, expr.span) return ct_eval_field_value(state, base_id, expr.name, expr.span)
case .Index: case .Index:
index_id, index_flow, index_ok := ct_eval_expr(state, expr.right, types.INVALID, depth+1) index_id, index_flow, index_ok := ct_eval_expr(state, expr.right, types.USIZE, depth+1)
if !index_ok || index_flow.kind != .Normal { if !index_ok || index_flow.kind != .Normal {
return INVALID_CT_VALUE, index_flow, index_ok return INVALID_CT_VALUE, index_flow, index_ok
} }
index_type := state.values[index_id].type index_type := state.values[index_id].type
index_representation := types.runtime_representation(index_type, store) if !types.equal(index_type, types.USIZE) {
index_literal := is_numeric_constant_expr(checker, expr.right) return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(
if !types.is_concrete_integer(index_representation) || state,
!index_literal && !can_implicitly_convert_type(checker, index_representation, types.USIZE) { .Not_Comptime,
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "comptime index must be coercible to usize") checker.ast_module.exprs[expr.right].span,
"index must have type usize, got %s",
type_label(checker, index_type),
)
} }
index_value, index_is_int := ct_integer_value(state, index_id) index_value, index_is_int := ct_integer_value(state, index_id)
if !index_is_int || index_value < 0 || index_value > i128(0x7fff_ffff) { if !index_is_int || index_value < 0 || index_value > i128(0x7fff_ffff) {
@@ -1962,16 +2007,19 @@ ct_eval_slice_expr :: proc(state: ^Ct_State, expr: ast.Expr, depth: int) -> (Ct_
if bound == ast.INVALID_EXPR { if bound == ast.INVALID_EXPR {
continue continue
} }
value, bound_flow, bound_ok := ct_eval_expr(state, bound, types.INVALID, depth+1) value, bound_flow, bound_ok := ct_eval_expr(state, bound, types.USIZE, depth+1)
if !bound_ok || bound_flow.kind != .Normal { if !bound_ok || bound_flow.kind != .Normal {
return INVALID_CT_VALUE, bound_flow, bound_ok return INVALID_CT_VALUE, bound_flow, bound_ok
} }
bound_type := state.values[value].type bound_type := state.values[value].type
bound_representation := types.runtime_representation(bound_type, store) if !types.equal(bound_type, types.USIZE) {
bound_literal := is_numeric_constant_expr(checker, bound) return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(
if !types.is_concrete_integer(bound_representation) || state,
!bound_literal && !can_implicitly_convert_type(checker, bound_representation, types.USIZE) { .Not_Comptime,
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "slice bounds must be coercible to usize") checker.ast_module.exprs[bound].span,
"slice bound must have type usize, got %s",
type_label(checker, bound_type),
)
} }
integer, integer_ok := ct_integer_value(state, value) integer, integer_ok := ct_integer_value(state, value)
if !integer_ok || integer < 0 || integer > i128(0x7fff_ffff) { if !integer_ok || integer < 0 || integer > i128(0x7fff_ffff) {
@@ -2352,6 +2400,16 @@ ct_eval_place :: proc(
if !index_ok || index_flow.kind != .Normal { if !index_ok || index_flow.kind != .Normal {
return INVALID_CT_PLACE, types.INVALID, false, index_flow, index_ok return INVALID_CT_PLACE, types.INVALID, false, index_flow, index_ok
} }
index_type := state.values[index_value].type
if !types.equal(index_type, types.USIZE) {
return INVALID_CT_PLACE, types.INVALID, false, ct_flow(.Normal), ct_failf(
state,
.Not_Comptime,
checker.ast_module.exprs[expr.right].span,
"index must have type usize, got %s",
type_label(checker, index_type),
)
}
index_int, int_ok := ct_integer_value(state, index_value) index_int, int_ok := ct_integer_value(state, index_value)
if !int_ok || index_int < 0 || index_int > i128(0x7fff_ffff) { if !int_ok || index_int < 0 || index_int > i128(0x7fff_ffff) {
return INVALID_CT_PLACE, types.INVALID, false, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "comptime index must be a non-negative integer") return INVALID_CT_PLACE, types.INVALID, false, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "comptime index must be a non-negative integer")
@@ -4983,6 +5041,11 @@ ct_exec_statements :: proc(
} else { } else {
declared := type_from_syntax(checker, statement.type, state.pkg, state.file, active_state=state) declared := type_from_syntax(checker, statement.type, state.pkg, state.file, active_state=state)
expected := declared if types.is_valid(declared) && !types.is_void(declared) else types.INVALID expected := declared if types.is_valid(declared) && !types.is_void(declared) else types.INVALID
open_integer := false
if !is_runtime_type(checker, declared) {
constant := eval_integer_constant_in_context(checker, statement.expr, state.pkg, state.file)
open_integer = constant.kind == .Value
}
value, expr_flow, expr_ok := ct_eval_expr(state, statement.expr, expected, depth+1) value, expr_flow, expr_ok := ct_eval_expr(state, statement.expr, expected, depth+1)
ok = expr_ok ok = expr_ok
flow = expr_flow flow = expr_flow
@@ -4991,7 +5054,14 @@ ct_exec_statements :: proc(
value, ok = ct_coerce_value(state, value, expected, statement.span) value, ok = ct_coerce_value(state, value, expected, statement.span)
} }
if ok && statement.name != checker.sink_symbol { if ok && statement.name != checker.sink_symbol {
ct_bind_value(state, statement.name, state.values[value].type, value, !statement.immutable) ct_bind_value(
state,
statement.name,
state.values[value].type,
value,
!statement.immutable,
open_integer=open_integer,
)
} }
} }
} }
+87 -1
View File
@@ -1867,6 +1867,92 @@ many_item_pointer_slices_require_end_bound :: proc(t: ^testing.T) {
testing.expect_value(t, end_bound_errors, 2) testing.expect_value(t, end_bound_errors, 2)
} }
@(test)
indices_and_slice_bounds_require_usize :: proc(t: ^testing.T) {
text := `Index :: distinct u32
main func() void {
values [2]i32 := [1, 2]
index := 1
start := 0
end := 1
small u32 := 0
id Index := Index(0)
_ = values[index]
_ = values[start..end]
_ = values[small]
_ = values[id]
_ = values[small..]
_ = values[..id]
}
`
source_file := source.Source{path="test.bro", text=text}
diagnostics := source.init_diagnostics(&source_file)
defer source.destroy_diagnostics(&diagnostics)
symbols := symbol.init_table()
defer symbol.destroy_table(&symbols)
stream := lexer.lex(&source_file, &diagnostics, &symbols)
defer delete(stream.items)
ast_module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&ast_module)
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
defer hir.destroy_module(&hir_module)
index_errors, bound_errors := 0, 0
for diagnostic in diagnostics.items {
index_errors += 1 if strings.contains(diagnostic.message, "index must have type usize") else 0
bound_errors += 1 if strings.contains(diagnostic.message, "slice bound must have type usize") else 0
}
testing.expect_value(t, len(diagnostics.items), 4)
testing.expect_value(t, index_errors, 2)
testing.expect_value(t, bound_errors, 2)
}
@(test)
comptime_indices_infer_usize_and_reject_explicit_integer_types :: proc(t: ^testing.T) {
text := `good func($items [2]u8) u8 {
start := 0
end := 1
part :: items[start..end]
return part[start]
}
bad_index func($items [2]u8) u8 {
cursor u32 := 0
return items[cursor]
}
bad_bound func($items [2]u8) u8 {
start u32 := 0
return items[start..][0]
}
GOOD :: $good([7, 8])
BAD_INDEX :: $bad_index([7, 8])
BAD_BOUND :: $bad_bound([7, 8])
main func() void {
_ = GOOD
_ = BAD_INDEX
_ = BAD_BOUND
}
`
source_file := source.Source{path="test.bro", text=text}
diagnostics := source.init_diagnostics(&source_file)
defer source.destroy_diagnostics(&diagnostics)
symbols := symbol.init_table()
defer symbol.destroy_table(&symbols)
stream := lexer.lex(&source_file, &diagnostics, &symbols)
defer delete(stream.items)
ast_module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&ast_module)
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
defer hir.destroy_module(&hir_module)
testing.expect_value(t, len(diagnostics.items), 2)
index_error, bound_error := false, false
for diagnostic in diagnostics.items {
index_error = index_error || strings.contains(diagnostic.message, "index must have type usize, got u32")
bound_error = bound_error || strings.contains(diagnostic.message, "slice bound must have type usize, got u32")
}
testing.expect(t, index_error && bound_error)
}
@(test) @(test)
layout_builtins_compile_and_run :: proc(t: ^testing.T) { layout_builtins_compile_and_run :: proc(t: ^testing.T) {
directory := "/tmp/brolang-test-layout-builtins" directory := "/tmp/brolang-test-layout-builtins"
@@ -6107,7 +6193,7 @@ milestone_24_rejects_invalid_forms :: proc(t: ^testing.T) {
} }
cases := [?]Case{ cases := [?]Case{
{"examples/programs/index_signed_error", "/tmp/brolang-test-index-signed-error"}, {"examples/programs/index_signed_error", "/tmp/brolang-test-index-signed-error"},
{"examples/programs/index_int_constraint_error", "/tmp/brolang-test-index-int-constraint-error"}, {"examples/programs/index_unsigned_error", "/tmp/brolang-test-index-unsigned-error"},
{"examples/programs/scalar_cast_error", "/tmp/brolang-test-scalar-cast-error"}, {"examples/programs/scalar_cast_error", "/tmp/brolang-test-scalar-cast-error"},
{"examples/programs/array_const_size_error", "/tmp/brolang-test-array-const-size-error"}, {"examples/programs/array_const_size_error", "/tmp/brolang-test-array-const-size-error"},
} }
+2 -2
View File
@@ -82,8 +82,8 @@ main func() i32 {
if bits != 255 { return 10 } if bits != 255 { return 10 }
values [10]u8 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] values [10]u8 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
if values[LocalID(4)] != 4 { return 11 } if values[usize(LocalID(4))] != 4 { return 11 }
section []u8 := values[LocalID(2)..LocalID(5)] section []u8 := values[usize(LocalID(2))..usize(LocalID(5))]
if section.len != 3 or section[usize(0)] != 2 or section[usize(2)] != 4 { return 12 } if section.len != 3 or section[usize(0)] != 2 or section[usize(2)] != 4 { return 12 }
if u32(id) != 7 or usize(id) != 7 or f64(id) != 7.0 { return 13 } if u32(id) != 7 or usize(id) != 7 or f64(id) != 7.0 { return 13 }
@@ -1,6 +1,6 @@
main func() i32 { main func() i32 {
items [3]mut i32 := undefined items [3]mut i32 := undefined
i int := 1 i u32 := 1
items[i] = 42 items[i] = 42
return 0 return 0
} }
+1 -1
View File
@@ -52,7 +52,7 @@ main func() i32 {
items[0] = 10 items[0] = 10
items[1] = 20 items[1] = 20
idx u8 := 2 idx usize := 2
items[idx] = items[0] + items[1] items[idx] = items[0] + items[1]
if (items[2] != 30) return 1 if (items[2] != 30) return 1