implicit address-taking for array slices
This commit is contained in:
@@ -144,6 +144,13 @@
|
|||||||
9. allow pointer field access pass-through (implemented)
|
9. allow pointer field access pass-through (implemented)
|
||||||
- having a pointer (`ptr`) to a struct, we should allow access through `ptr.field` as opposed to mandating `ptr^.field`
|
- having a pointer (`ptr`) to a struct, we should allow access through `ptr.field` as opposed to mandating `ptr^.field`
|
||||||
|
|
||||||
|
10. make slice expressions on array variables implicitly address-taking (implemented)
|
||||||
|
- zig's slice expression on an array variable handles the address-taking implicitly (nice ergonomics)
|
||||||
|
- `arr[a..b]` on an array variable now slices without the explicit `&`; the
|
||||||
|
explicit `(&arr)[a..b]` pointer-to-array form keeps working unchanged
|
||||||
|
- array rvalues (e.g. a by-value array return) are materialized into a
|
||||||
|
temporary before slicing, matching the for-loop iterable lowering
|
||||||
|
|
||||||
## A word on multi-unwrap
|
## 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 none, subsequent expressions are not evaluated.
|
||||||
|
|||||||
@@ -244,9 +244,26 @@ lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instructi
|
|||||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
})
|
})
|
||||||
case .Slice:
|
case .Slice:
|
||||||
container := lower_nested_expr(state, expr.left)
|
left_type := state.hir_module.exprs[expr.left].type
|
||||||
if types.is_array(state.hir_module.exprs[expr.left].type, &state.hir_module.types) {
|
container: ir.Instruction_Id
|
||||||
container = lower_location(state, expr.left)
|
if types.is_array(left_type, &state.hir_module.types) {
|
||||||
|
if hir_expr_is_location(state, expr.left) {
|
||||||
|
container = lower_location(state, expr.left)
|
||||||
|
} else {
|
||||||
|
value := lower_nested_expr(state, expr.left)
|
||||||
|
container = append_instruction(state, ir.Instruction{
|
||||||
|
op=.Alloca, span=expr.span, type=left_type,
|
||||||
|
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||||
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
|
})
|
||||||
|
append_instruction(state, ir.Instruction{
|
||||||
|
op=.Store, span=expr.span, type=left_type,
|
||||||
|
target=ir.INVALID_REF, a=container, b=value,
|
||||||
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container = lower_nested_expr(state, expr.left)
|
||||||
}
|
}
|
||||||
args := make([]ir.Instruction_Id, len(expr.args), state.allocator)
|
args := make([]ir.Instruction_Id, len(expr.args), state.allocator)
|
||||||
for arg, index in expr.args {
|
for arg, index in expr.args {
|
||||||
|
|||||||
@@ -1017,6 +1017,78 @@ immutable_pointer_and_slice_bindings_preserve_mutable_pointees :: proc(t: ^testi
|
|||||||
testing.expect_value(t, len(diagnostics.items), 0)
|
testing.expect_value(t, len(diagnostics.items), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
slicing_an_array_variable_takes_its_address_implicitly :: proc(t: ^testing.T) {
|
||||||
|
// Milestone 10: `arr[a..b]` on an array variable slices without an explicit
|
||||||
|
// `&`. The slice operand must be a pointer to the array (getelementptr off a
|
||||||
|
// `ptr`), not the array value.
|
||||||
|
text := `sink :: func(s []i32) i32 {
|
||||||
|
return s[0]
|
||||||
|
}
|
||||||
|
main :: func() i32 {
|
||||||
|
arr [4]i32 = [10, 20, 30, 40]
|
||||||
|
full :: sink(arr[..])
|
||||||
|
part :: sink(arr[1..3])
|
||||||
|
return full + part
|
||||||
|
}
|
||||||
|
`
|
||||||
|
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)
|
||||||
|
ir_module := lower.lower(&hir_module)
|
||||||
|
defer ir.destroy_module(&ir_module)
|
||||||
|
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
|
||||||
|
defer delete(llvm_text)
|
||||||
|
|
||||||
|
testing.expect_value(t, len(diagnostics.items), 0)
|
||||||
|
testing.expect(t, strings.contains(llvm_text, "getelementptr [4 x i32], ptr"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
slicing_an_array_rvalue_materializes_a_temporary :: proc(t: ^testing.T) {
|
||||||
|
// The checker accepts slicing a non-location array (here, a by-value array
|
||||||
|
// return). Lowering must store it into a temporary and slice that address;
|
||||||
|
// otherwise the slice operand is an array value, which is an invalid pointer.
|
||||||
|
text := `make_arr :: func() [4]i32 {
|
||||||
|
return [1, 2, 3, 4]
|
||||||
|
}
|
||||||
|
sink :: func(s []i32) i32 {
|
||||||
|
return s[0]
|
||||||
|
}
|
||||||
|
main :: func() i32 {
|
||||||
|
return sink(make_arr()[0..])
|
||||||
|
}
|
||||||
|
`
|
||||||
|
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)
|
||||||
|
ir_module := lower.lower(&hir_module)
|
||||||
|
defer ir.destroy_module(&ir_module)
|
||||||
|
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
|
||||||
|
defer delete(llvm_text)
|
||||||
|
|
||||||
|
testing.expect_value(t, len(diagnostics.items), 0)
|
||||||
|
// The materialization store of the array rvalue into its temporary.
|
||||||
|
testing.expect(t, strings.contains(llvm_text, "store [4 x i32]"))
|
||||||
|
testing.expect(t, strings.contains(llvm_text, "getelementptr [4 x i32], ptr"))
|
||||||
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
c_variadic_calls_promote_extras_and_emit_variadic_llvm :: proc(t: ^testing.T) {
|
c_variadic_calls_promote_extras_and_emit_variadic_llvm :: proc(t: ^testing.T) {
|
||||||
text := `variadic :: c_func(tag c_int, ...) c_int
|
text := `variadic :: c_func(tag c_int, ...) c_int
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ main :: func() i32 {
|
|||||||
item^ = item^ + 1
|
item^ = item^ + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
view []mut i32 = (&items)[..]
|
view []mut i32 = items[..]
|
||||||
for view |@item, index| {
|
for view |@item, index| {
|
||||||
item^ = item^ + 1
|
item^ = item^ + 1
|
||||||
_ = index
|
_ = index
|
||||||
|
|||||||
+2
-2
@@ -71,14 +71,14 @@ main :: func() i32 {
|
|||||||
Player { id = PlayerID(4), name = "Grace", tier = .gold, score = 33, streak = 5, active = true },
|
Player { id = PlayerID(4), name = "Grace", tier = .gold, score = 33, streak = 5, active = true },
|
||||||
]
|
]
|
||||||
|
|
||||||
apply_decay((&players)[..])
|
apply_decay(players[..])
|
||||||
|
|
||||||
for (&players) |@player, index| {
|
for (&players) |@player, index| {
|
||||||
score :: projected_score(player^)
|
score :: projected_score(player^)
|
||||||
_ = printf("%d: %s projected=%d\n", index, player.name, score)
|
_ = printf("%d: %s projected=%d\n", index, player.name, score)
|
||||||
}
|
}
|
||||||
|
|
||||||
if best_player((&players)[..]) |winner : projected_score(winner^) >= 80| {
|
if best_player(players[..]) |winner : projected_score(winner^) >= 80| {
|
||||||
_ = printf("winner: %s\n", winner.name)
|
_ = printf("winner: %s\n", winner.name)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user