mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-28 07:51:33 +00:00
Merge pull request #7457 from kalsprite/const_array_broadcast
broadcast a constant into every array level
This commit is contained in:
@@ -791,6 +791,20 @@ gb_internal lbValue lb_const_value_bit_field(lbModule *m, Type *type, Ast *value
|
||||
}
|
||||
|
||||
|
||||
// A value assigned to an array is broadcast to every element, and the checker peels every array
|
||||
// level before matching it, so the literal may be for a type below the immediate element type.
|
||||
gb_internal bool lb_const_value_is_broadcast(Type *elem_type, Type *lit_type) {
|
||||
if (are_types_identical(lit_type, elem_type)) {
|
||||
return true;
|
||||
}
|
||||
// `[4][8]Item = Item{...}`, one level is consumed per recursion
|
||||
if (are_types_identical(lit_type, core_broadcastable_elem_type(elem_type))) {
|
||||
return true;
|
||||
}
|
||||
// `[8]U = U(Item{...})`, a union element takes the value as one of its variants
|
||||
return type_conversion_is_variant(elem_type, lit_type);
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) {
|
||||
if (cc.allow_local) {
|
||||
cc.is_rodata = false;
|
||||
@@ -1504,7 +1518,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
if (are_types_identical(value.value_compound->tav.type, elem_type)) {
|
||||
if (lb_const_value_is_broadcast(elem_type, value.value_compound->tav.type)) {
|
||||
// Compound is of array item type; expand its value to all items in array.
|
||||
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
|
||||
..\..\..\odin test ..\test_issue_7008.odin %COMMON% || exit /b
|
||||
..\..\..\odin check ..\test_issue_7012.odin -no-entry-point %COMMON% || exit /b
|
||||
..\..\..\odin check ..\test_issue_7260.odin -no-entry-point %COMMON% || exit /b
|
||||
..\..\..\odin test ..\test_issue_bool_to_be_conversion.odin %COMMON% || exit /b
|
||||
..\..\..\odin test ..\test_issue_bool_comparison_truthiness.odin %COMMON% || exit /b
|
||||
..\..\..\odin test ..\test_issue_const_array_broadcast.odin %COMMON% || exit /b
|
||||
..\..\..\odin check ..\test_issue_7336.odin -no-entry-point %COMMON% || exit /b
|
||||
..\..\..\odin check ..\test_issue_ellipsis_type_call.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "10" || exit /b
|
||||
..\..\..\odin check ..\test_issue_foreign_redeclaration.odin -no-entry-point %COMMON% || exit /b
|
||||
|
||||
@@ -98,6 +98,8 @@ $ODIN build ../test_issue_7167.odin $COMMON
|
||||
$ODIN build ../test_issue_7188.odin $COMMON
|
||||
$ODIN check ../test_issue_7260.odin -no-entry-point $COMMON_CHECK
|
||||
$ODIN test ../test_issue_bool_to_be_conversion.odin $COMMON
|
||||
$ODIN test ../test_issue_bool_comparison_truthiness.odin $COMMON
|
||||
$ODIN test ../test_issue_const_array_broadcast.odin $COMMON
|
||||
$ODIN test ../test_issue_swizzle_multi_assign.odin $COMMON
|
||||
|
||||
$ODIN check ../test_issue_foreign_redeclaration.odin -no-entry-point $COMMON_CHECK
|
||||
|
||||
82
tests/issues/test_issue_const_array_broadcast.odin
Normal file
82
tests/issues/test_issue_const_array_broadcast.odin
Normal file
@@ -0,0 +1,82 @@
|
||||
package test_issues
|
||||
|
||||
import "core:testing"
|
||||
|
||||
// A value assigned to an array is broadcast to every element of every level, but the constant
|
||||
// lowering only recognised a literal whose type was the immediate element type. `[4][8]Item` has
|
||||
// two levels to cross and `[8]U` has a union variant to reach, so both were taken for array
|
||||
// literals and tripped an assertion in the compiler.
|
||||
|
||||
@(private="file")
|
||||
Item :: struct {
|
||||
stage: int,
|
||||
size: int,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
U :: union {
|
||||
Item,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
Desc :: struct {
|
||||
items: [4][8]Item,
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
nested_global: [4][8]Item = Item{stage = 1, size = 64}
|
||||
|
||||
@(private="file")
|
||||
union_global: [8]U = U(Item{stage = 2, size = 65})
|
||||
|
||||
@(test)
|
||||
const_array_broadcast_nested :: proc(t: ^testing.T) {
|
||||
expected :: Item{stage = 1, size = 64}
|
||||
|
||||
for row in nested_global {
|
||||
for item in row {
|
||||
testing.expect_value(t, item, expected)
|
||||
}
|
||||
}
|
||||
|
||||
nested_local: [4][8]Item = Item{stage = 1, size = 64}
|
||||
testing.expect_value(t, nested_local, nested_global)
|
||||
|
||||
d := Desc{items = Item{stage = 1, size = 64}}
|
||||
testing.expect_value(t, d.items, nested_global)
|
||||
|
||||
// positional fields reach the same path
|
||||
positional: [4][8]Item = Item{1, 64}
|
||||
testing.expect_value(t, positional, nested_global)
|
||||
|
||||
deep: [2][3][4]int = 7
|
||||
testing.expect_value(t, deep[1][2][3], 7)
|
||||
}
|
||||
|
||||
@(test)
|
||||
const_array_broadcast_union :: proc(t: ^testing.T) {
|
||||
expected :: Item{stage = 2, size = 65}
|
||||
|
||||
for u in union_global {
|
||||
item, ok := u.(Item)
|
||||
testing.expect(t, ok, "every element should hold the Item variant")
|
||||
testing.expect_value(t, item, expected)
|
||||
}
|
||||
|
||||
union_local: [8]U = U(Item{stage = 2, size = 65})
|
||||
testing.expect_value(t, union_local, union_global)
|
||||
}
|
||||
|
||||
@(test)
|
||||
const_array_literals_unchanged :: proc(t: ^testing.T) {
|
||||
// a literal for the array's own type is not a broadcast
|
||||
indexed: [4]Item = {0..<2 = Item{stage = 3, size = 66}, 3 = Item{stage = 4, size = 67}}
|
||||
testing.expect_value(t, indexed[0], Item{stage = 3, size = 66})
|
||||
testing.expect_value(t, indexed[1], Item{stage = 3, size = 66})
|
||||
testing.expect_value(t, indexed[2], Item{})
|
||||
testing.expect_value(t, indexed[3], Item{stage = 4, size = 67})
|
||||
|
||||
positional: [3]Item = {Item{stage = 5, size = 68}, {}, {}}
|
||||
testing.expect_value(t, positional[0], Item{stage = 5, size = 68})
|
||||
testing.expect_value(t, positional[2], Item{})
|
||||
}
|
||||
Reference in New Issue
Block a user