mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Foreach over distinct iterable would ignore operator(len).
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
- Fix thread tests.
|
||||
- Detect recursion errors on non-recursive mutexes in safe mode.
|
||||
- Foreach over distinct pointer failed to be caught as error #1506.
|
||||
- Foreach over distinct iterable would ignore operator(len).
|
||||
|
||||
### Stdlib changes
|
||||
- Additional init functions for hashmap.
|
||||
|
||||
@@ -1463,10 +1463,6 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
// Check that we can even index this expression.
|
||||
|
||||
Type *value_type = type_get_indexed_type(enumerator->type);
|
||||
// Special case, we might have "distinct Foo = char*" in which case the
|
||||
// deref didn't happen above, but it will get a value_type.
|
||||
// However, that would make the code later assume it's possible
|
||||
// To use foreach on it.
|
||||
if (canonical->type_kind == TYPE_DISTINCT && type_flatten(canonical)->type_kind == TYPE_POINTER)
|
||||
{
|
||||
value_type = NULL;
|
||||
@@ -1478,20 +1474,19 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
Decl *index_macro = NULL;
|
||||
Type *index_type = type_usz;
|
||||
|
||||
if (!value_type)
|
||||
if (!value_type || canonical->type_kind == TYPE_DISTINCT)
|
||||
{
|
||||
len = sema_find_operator(context, enumerator->type, OVERLOAD_LEN);
|
||||
Decl *by_val = sema_find_operator(context, enumerator->type, OVERLOAD_ELEMENT_AT);
|
||||
Decl *by_ref = sema_find_operator(context, enumerator->type, OVERLOAD_ELEMENT_REF);
|
||||
if (!len || (!by_val && !by_ref))
|
||||
{
|
||||
SEMA_ERROR(enumerator, "It's not possible to enumerate an expression of type %s.", type_quoted_error_string(enumerator->type));
|
||||
return false;
|
||||
if (value_type) goto SKIP_OVERLOAD;
|
||||
RETURN_SEMA_ERROR(enumerator, "It's not possible to enumerate an expression of type %s.", type_quoted_error_string(enumerator->type));
|
||||
}
|
||||
if (!by_ref && value_by_ref)
|
||||
{
|
||||
SEMA_ERROR(enumerator, "%s does not support 'foreach' by reference, but you iterate by value.", type_quoted_error_string(enumerator->type));
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(enumerator, "%s does not support 'foreach' by reference, but you iterate by value.", type_quoted_error_string(enumerator->type));
|
||||
}
|
||||
if (!decl_ok(len) || !decl_ok(by_val) || !decl_ok(by_ref)) return false;
|
||||
index_macro = value_by_ref ? by_ref : by_val;
|
||||
@@ -1499,13 +1494,13 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
index_type = index_macro->func_decl.signature.params[1]->type;
|
||||
if (!type_is_integer(index_type))
|
||||
{
|
||||
SEMA_ERROR(enumerator, "Only integer indexed types may be used with foreach.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(enumerator, "Only integer indexed types may be used with foreach.");
|
||||
}
|
||||
TypeInfoId rtype = index_macro->func_decl.signature.rtype;
|
||||
value_type = rtype ? type_infoptr(rtype)->type : NULL;
|
||||
}
|
||||
|
||||
SKIP_OVERLOAD:;
|
||||
|
||||
TypeInfo *type_info = vartype(var);
|
||||
// Set up the value, assigning the type as needed.
|
||||
@@ -1531,15 +1526,13 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
index_var_type = idx_type_info->type;
|
||||
if (type_is_optional(index_var_type))
|
||||
{
|
||||
SEMA_ERROR(idx_type_info, "The index may not be an optional.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(idx_type_info, "The index may not be an optional.");
|
||||
}
|
||||
if (!type_is_integer(type_flatten(index_var_type)))
|
||||
{
|
||||
SEMA_ERROR(idx_type_info,
|
||||
"Index must be an integer type, '%s' is not valid.",
|
||||
type_to_error_string(index_var_type));
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(idx_type_info,
|
||||
"Index must be an integer type, '%s' is not valid.",
|
||||
type_to_error_string(index_var_type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
67
test/test_suite/statements/foreach_distinct_iterable.c3t
Normal file
67
test/test_suite/statements/foreach_distinct_iterable.c3t
Normal file
@@ -0,0 +1,67 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std;
|
||||
distinct TypeA = char[];
|
||||
|
||||
fn char TypeA.get(self, usz i) @operator([]) {
|
||||
return ((char[])self)[i];
|
||||
}
|
||||
|
||||
fn usz TypeA.len(self) @operator(len)
|
||||
{
|
||||
return self.len;
|
||||
}
|
||||
|
||||
fn int main() {
|
||||
TypeA x = "AAAAA";
|
||||
foreach(y : x)
|
||||
{
|
||||
int z = y;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
et i64 %2
|
||||
}
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%x = alloca %"char[]", align 8
|
||||
%.anon = alloca i64, align 8
|
||||
%.anon1 = alloca i64, align 8
|
||||
%y = alloca i8, align 1
|
||||
%z = alloca i32, align 4
|
||||
store %"char[]" { ptr @.str, i64 5 }, ptr %x, align 8
|
||||
%lo = load ptr, ptr %x, align 8
|
||||
%ptradd = getelementptr inbounds i8, ptr %x, i64 8
|
||||
%hi = load i64, ptr %ptradd, align 8
|
||||
%0 = call i64 @test.TypeA.len(ptr %lo, i64 %hi)
|
||||
store i64 %0, ptr %.anon, align 8
|
||||
store i64 0, ptr %.anon1, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.cond: ; preds = %loop.body, %entry
|
||||
%1 = load i64, ptr %.anon1, align 8
|
||||
%2 = load i64, ptr %.anon, align 8
|
||||
%lt = icmp ult i64 %1, %2
|
||||
br i1 %lt, label %loop.body, label %loop.exit
|
||||
|
||||
loop.body: ; preds = %loop.cond
|
||||
%lo2 = load ptr, ptr %x, align 8
|
||||
%ptradd3 = getelementptr inbounds i8, ptr %x, i64 8
|
||||
%hi4 = load i64, ptr %ptradd3, align 8
|
||||
%3 = load i64, ptr %.anon1, align 8
|
||||
%4 = call i8 @test.TypeA.get(ptr %lo2, i64 %hi4, i64 %3)
|
||||
store i8 %4, ptr %y, align 1
|
||||
%5 = load i8, ptr %y, align 1
|
||||
%zext = zext i8 %5 to i32
|
||||
store i32 %zext, ptr %z, align 4
|
||||
%6 = load i64, ptr %.anon1, align 8
|
||||
%addnuw = add nuw i64 %6, 1
|
||||
store i64 %addnuw, ptr %.anon1, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.exit: ; preds = %loop.cond
|
||||
ret i32 0
|
||||
Reference in New Issue
Block a user