mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix bug preventing optionals from being used in ranges or as indices.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
- Prevent methods from using names of properties or fields. #1638
|
||||
- b64 / hex data strings can now be used with \` as well.
|
||||
- Contracts on generic modules would evaluate too late, sometimes not catching the error until it already occurred elsewhere.
|
||||
- Fix bug preventing optionals from being used in ranges or as indices.
|
||||
|
||||
### Stdlib changes
|
||||
- Add `io::MultiReader`, `io::MultiWriter`, and `io::TeeReader` structs.
|
||||
|
||||
@@ -681,6 +681,7 @@ typedef struct
|
||||
bool end_from_end : 1;
|
||||
bool is_len : 1;
|
||||
bool is_range : 1;
|
||||
bool is_optional : 1;
|
||||
union
|
||||
{
|
||||
struct
|
||||
|
||||
@@ -607,6 +607,7 @@ bool cast_to_index(SemaContext *context, Expr *index, Type *subscripted_type)
|
||||
Type *type = index->type;
|
||||
RETRY:
|
||||
type = type_flat_distinct_inline(type);
|
||||
type = type_no_optional(type);
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_I8:
|
||||
|
||||
@@ -3043,6 +3043,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
// Cast to an appropriate type for index.
|
||||
if (!cast_to_index(context, index, subscripted->type)) return false;
|
||||
|
||||
optional |= IS_OPTIONAL(index);
|
||||
// Check range
|
||||
bool remove_from_back = false;
|
||||
if (!sema_slice_index_is_in_range(context, current_type, index, false, start_from_end, &remove_from_back)) return false;
|
||||
@@ -3149,7 +3150,7 @@ typedef enum RangeEnv
|
||||
RANGE_FLEXIBLE,
|
||||
} RangeEnv;
|
||||
|
||||
INLINE bool sema_expre_analyse_range_internal(SemaContext *context, Range *range, Type *indexed_type, ArrayIndex len, RangeEnv env)
|
||||
INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, Type *indexed_type, ArrayIndex len, RangeEnv env)
|
||||
{
|
||||
Expr *start = exprptr(range->start);
|
||||
ASSERT0(start);
|
||||
@@ -3160,9 +3161,13 @@ INLINE bool sema_expre_analyse_range_internal(SemaContext *context, Range *range
|
||||
|
||||
if (!cast_to_index(context, start, indexed_type)) return false;
|
||||
if (end && !cast_to_index(context, end, indexed_type)) return false;
|
||||
if (end && end->type != start->type)
|
||||
Type *end_type = end ? type_no_optional(end->type) : NULL;
|
||||
Type *start_type = type_no_optional(start->type);
|
||||
if (end && IS_OPTIONAL(end)) range->is_optional = true;
|
||||
if (IS_OPTIONAL(start)) range->is_optional = true;
|
||||
if (end && end_type != start_type)
|
||||
{
|
||||
Type *common = type_find_max_type(start->type, end->type);
|
||||
Type *common = type_find_max_type(start_type, end_type);
|
||||
if (!common)
|
||||
{
|
||||
SourceSpan span = start->span;
|
||||
@@ -3316,7 +3321,7 @@ static inline bool sema_expr_analyse_range(SemaContext *context, Range *range, T
|
||||
return true;
|
||||
case RESOLVE_NOT_DONE:
|
||||
range->status = RESOLVE_RUNNING;
|
||||
if (!sema_expre_analyse_range_internal(context, range, indexed_type, len, env))
|
||||
if (!sema_expr_analyse_range_internal(context, range, indexed_type, len, env))
|
||||
{
|
||||
range->status = RESOLVE_NOT_DONE;
|
||||
return false;
|
||||
@@ -3421,7 +3426,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr, Che
|
||||
ArrayIndex length = sema_len_from_expr(subscripted);
|
||||
Range *range = &expr->slice_expr.range;
|
||||
if (!sema_expr_analyse_range(context, range, subscripted->type, length, env)) return false;
|
||||
|
||||
if (range->is_optional) optional = true;
|
||||
if (check == CHECK_VALUE && sema_cast_const(subscripted) && range->range_type == RANGE_CONST_RANGE)
|
||||
{
|
||||
switch (subscripted->const_expr.const_kind)
|
||||
|
||||
120
test/test_suite/slices/slice_optional_index.c3t
Normal file
120
test/test_suite/slices/slice_optional_index.c3t
Normal file
@@ -0,0 +1,120 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
|
||||
fn void test()
|
||||
{
|
||||
int[] a = { 1, 2, 3 };
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int! b = i == 0 ? SearchResult.MISSING? : i;
|
||||
int[]! y = a[:b];
|
||||
int[]! w = a[b..];
|
||||
int! z = a[b];
|
||||
}
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
store %"int[]" %1, ptr %a, align 8
|
||||
store i32 0, ptr %i, align 4
|
||||
br label %loop.cond
|
||||
|
||||
loop.cond: ; preds = %after_assign15, %entry
|
||||
%2 = load i32, ptr %i, align 4
|
||||
%lt = icmp slt i32 %2, 3
|
||||
br i1 %lt, label %loop.body, label %loop.exit
|
||||
|
||||
loop.body: ; preds = %loop.cond
|
||||
%3 = load i32, ptr %i, align 4
|
||||
%eq = icmp eq i32 %3, 0
|
||||
br i1 %eq, label %cond.lhs, label %cond.rhs
|
||||
|
||||
cond.lhs: ; preds = %loop.body
|
||||
store i64 ptrtoint (ptr @"std.core.builtin.SearchResult$MISSING" to i64), ptr %b.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
cond.rhs: ; preds = %loop.body
|
||||
%4 = load i32, ptr %i, align 4
|
||||
br label %cond.phi
|
||||
|
||||
cond.phi: ; preds = %cond.rhs
|
||||
store i32 %4, ptr %b, align 4
|
||||
store i64 0, ptr %b.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_assign: ; preds = %cond.phi, %cond.lhs
|
||||
%5 = load %"int[]", ptr %a, align 8
|
||||
%6 = extractvalue %"int[]" %5, 0
|
||||
%optval = load i64, ptr %b.f, align 8
|
||||
%not_err = icmp eq i64 %optval, 0
|
||||
%7 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %7, label %after_check, label %assign_optional
|
||||
|
||||
assign_optional: ; preds = %after_assign
|
||||
store i64 %optval, ptr %y.f, align 8
|
||||
br label %after_assign1
|
||||
|
||||
after_check: ; preds = %after_assign
|
||||
%8 = load i32, ptr %b, align 4
|
||||
%sext = sext i32 %8 to i64
|
||||
%add = add i64 0, %sext
|
||||
%size = sub i64 %add, 0
|
||||
%9 = insertvalue %"int[]" undef, ptr %6, 0
|
||||
%10 = insertvalue %"int[]" %9, i64 %size, 1
|
||||
store %"int[]" %10, ptr %y, align 8
|
||||
store i64 0, ptr %y.f, align 8
|
||||
br label %after_assign1
|
||||
|
||||
after_assign1: ; preds = %after_check, %assign_optional
|
||||
%11 = load %"int[]", ptr %a, align 8
|
||||
%12 = extractvalue %"int[]" %11, 0
|
||||
%optval2 = load i64, ptr %b.f, align 8
|
||||
%not_err3 = icmp eq i64 %optval2, 0
|
||||
%13 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
|
||||
br i1 %13, label %after_check5, label %assign_optional4
|
||||
|
||||
assign_optional4: ; preds = %after_assign1
|
||||
store i64 %optval2, ptr %w.f, align 8
|
||||
br label %after_assign8
|
||||
|
||||
after_check5: ; preds = %after_assign1
|
||||
%14 = load i32, ptr %b, align 4
|
||||
%sext6 = sext i32 %14 to i64
|
||||
%15 = extractvalue %"int[]" %11, 1
|
||||
%size7 = sub i64 %15, %sext6
|
||||
%ptroffset = getelementptr inbounds [4 x i8], ptr %12, i64 %sext6
|
||||
%16 = insertvalue %"int[]" undef, ptr %ptroffset, 0
|
||||
%17 = insertvalue %"int[]" %16, i64 %size7, 1
|
||||
store %"int[]" %17, ptr %w, align 8
|
||||
store i64 0, ptr %w.f, align 8
|
||||
br label %after_assign8
|
||||
|
||||
after_assign8: ; preds = %after_check5, %assign_optional4
|
||||
%18 = load ptr, ptr %a, align 8
|
||||
%optval9 = load i64, ptr %b.f, align 8
|
||||
%not_err10 = icmp eq i64 %optval9, 0
|
||||
%19 = call i1 @llvm.expect.i1(i1 %not_err10, i1 true)
|
||||
br i1 %19, label %after_check12, label %assign_optional11
|
||||
|
||||
assign_optional11: ; preds = %after_assign8
|
||||
store i64 %optval9, ptr %z.f, align 8
|
||||
br label %after_assign15
|
||||
|
||||
after_check12: ; preds = %after_assign8
|
||||
%20 = load i32, ptr %b, align 4
|
||||
%sext13 = sext i32 %20 to i64
|
||||
%ptroffset14 = getelementptr inbounds [4 x i8], ptr %18, i64 %sext13
|
||||
%21 = load i32, ptr %ptroffset14, align 4
|
||||
store i32 %21, ptr %z, align 4
|
||||
store i64 0, ptr %z.f, align 8
|
||||
br label %after_assign15
|
||||
|
||||
after_assign15: ; preds = %after_check12, %assign_optional11
|
||||
%22 = load i32, ptr %i, align 4
|
||||
%add16 = add i32 %22, 1
|
||||
store i32 %add16, ptr %i, align 4
|
||||
br label %loop.cond
|
||||
|
||||
loop.exit: ; preds = %loop.cond
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user