Incorrect subscript resolution #1519

This commit is contained in:
Christoffer Lerno
2024-10-04 20:50:48 +02:00
parent 6fabecac1a
commit cfc1d0d8f8
10 changed files with 78 additions and 32 deletions

View File

@@ -11,6 +11,7 @@
### Fixes
- `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489.
- Unexpected compile error using a typed constant with `copysign` #1517
- Incorrect subscript resolution #1519.
### Stdlib changes
- Remove unintended print of `char[]` as String

View File

@@ -2846,13 +2846,40 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
// 3. Check failability due to value.
bool optional = IS_OPTIONAL(subscripted);
Type *underlying_type = type_flatten(subscripted->type);
Decl *overload = NULL;
Type *index_type = NULL;
Expr *current_expr;
Type *current_type = subscripted->type->canonical;
if (current_type == type_untypedlist)
{
current_expr = subscripted;
}
else
{
current_expr = sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload);
if (!overload && !index_type && is_eval_ref)
{
// Maybe there is a [] overload?
if (sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload))
{
if (check_valid) goto VALID_FAIL_POISON;
RETURN_SEMA_ERROR(expr, "A function or macro with '@operator(&[])' is not defined for %s, "
"so you need && to take the address of the temporary.",
type_quoted_error_string(subscripted->type));
}
}
if (!index_type)
{
if (check_valid) goto VALID_FAIL_POISON;
RETURN_SEMA_ERROR(expr, "Indexing a value of type %s is not possible.", type_quoted_error_string(subscripted->type));
}
if (!overload) current_type = type_flatten(current_expr->type);
}
Type *current_type = underlying_type;
assert(current_type == current_type->canonical);
int64_t index_value = -1;
bool start_from_end = expr->subscript_expr.index.start_from_end;
if (start_from_end && (underlying_type->type_kind == TYPE_POINTER || underlying_type->type_kind == TYPE_FLEXIBLE_ARRAY))
if (start_from_end && (current_type->type_kind == TYPE_POINTER || current_type->type_kind == TYPE_FLEXIBLE_ARRAY))
{
if (check_valid) goto VALID_FAIL_POISON;
RETURN_SEMA_ERROR(index, "Indexing from the end is not allowed for pointers "
@@ -2897,8 +2924,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
(long long) size - 1);
}
}
// 4. If we are indexing into a complist
if (underlying_type == type_untypedlist)
if (current_type == type_untypedlist)
{
if (is_eval_ref)
{
@@ -2906,7 +2934,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
RETURN_SEMA_ERROR(subscripted, "You need to use && to take the address of a temporary.");
}
// 4a. This may either be an initializer list or a CT value
Expr *current_expr = subscripted;
while (subscripted->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
// 4b. Now we need to check that we actually have a valid type.
@@ -2921,29 +2948,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
}
if (!sema_cast_rvalue(context, subscripted)) return false;
Decl *overload = NULL;
Type *index_type = NULL;
Expr *current_expr = sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload);
if (!index_type)
{
if (!overload && is_eval_ref)
{
// Maybe there is a [] overload?
if (sema_expr_find_index_type_or_overload_for_subscript(context,
subscripted,
check,
&index_type,
&overload))
{
if (check_valid) goto VALID_FAIL_POISON;
RETURN_SEMA_ERROR(expr, "A function or macro with '@operator(&[])' is not defined for %s, "
"so you need && to take the address of the temporary.",
type_quoted_error_string(subscripted->type));
}
}
if (check_valid) goto VALID_FAIL_POISON;
RETURN_SEMA_ERROR(subscripted, "Cannot index %s.", type_quoted_error_string(subscripted->type));
}
if (overload)
{
if (start_from_end)

View File

@@ -1079,6 +1079,7 @@ bool type_is_user_defined(Type *type)
Type *type_get_indexed_type(Type *type)
{
RETRY:
if (type == type_voidptr) return NULL;
switch (type->type_kind)
{
case TYPE_POINTER:

View File

@@ -1,5 +1,5 @@
fn void test(int* array, usz n)
{
array[n] = 33;
n[array] = 33; // #error: Cannot index
n[array] = 33; // #error: Indexing a value of type
}

View File

@@ -1,3 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };

View File

@@ -1,4 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };

View File

@@ -1,3 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };

View File

@@ -1,3 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };

View File

@@ -0,0 +1,37 @@
// #target: macos-x64
module test;
import std::collections::list;
macro @test_list(a)
{
var $Type = $typeof(a);
$if $defined(a[0]) &&& $Type.typeid == List(<$typeof(a[0])>).typeid:
return 1;
$else
return 0;
$endif
}
fn int main(String[] args)
{
DString str = dstring::new("test");
return @test_list(str);
}
/* #expect: test.ll
define i32 @test.main(ptr %0, i64 %1) #0 {
entry:
%args = alloca %"char[][]", align 8
%str = alloca ptr, align 8
%a = alloca ptr, align 8
store ptr %0, ptr %args, align 8
%ptradd = getelementptr inbounds i8, ptr %args, i64 8
store i64 %1, ptr %ptradd, align 8
%lo = load i64, ptr @std.core.mem.allocator.thread_allocator, align 8
%hi = load ptr, ptr getelementptr inbounds (i8, ptr @std.core.mem.allocator.thread_allocator, i64 8), align 8
%2 = call ptr @std.core.dstring.new(ptr @.str, i64 4, i64 %lo, ptr %hi)
store ptr %2, ptr %str, align 8
%3 = load ptr, ptr %str, align 8
store ptr %3, ptr %a, align 8
ret i32 0
}

View File

@@ -8,12 +8,12 @@ fn void! test_clear() @test
s.append_repeat('x', 63);
assert(s.capacity() == 64);
assert(s.len() == 63);
char* addr = &s[0];
char* addr = (char*)s.str_view();
s.clear();
assert(s.capacity() == 64);
assert(s.len() == 0);
s.append_repeat('x', 63);
assert(s.capacity() == 64);
assert(s.len() == 63);
assert(addr == &s[0]);
assert(addr == (char*)s.str_view());
}