mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Cleanup and allow complex array length inference, e.g. "int[*][2][*] a = ..."
This commit is contained in:
@@ -2080,7 +2080,7 @@ bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type);
|
||||
bool cast(Expr *expr, Type *to_type);
|
||||
bool cast_may_bool_convert(Type *type);
|
||||
|
||||
Type *cast_infer_len(Type *to_infer, Type *actual_type);
|
||||
Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type);
|
||||
bool cast_to_index(Expr *index);
|
||||
|
||||
bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type);
|
||||
@@ -2396,7 +2396,7 @@ INLINE bool type_is_integer_unsigned(Type *type);
|
||||
INLINE bool type_is_integer_signed(Type *type);
|
||||
INLINE bool type_is_integer_or_bool_kind(Type *type);
|
||||
INLINE bool type_is_numeric(Type *type);
|
||||
INLINE bool type_is_len_inferred(Type *type);
|
||||
INLINE bool type_is_inferred(Type *type);
|
||||
INLINE bool type_underlying_is_numeric(Type *type);
|
||||
INLINE bool type_is_pointer(Type *type);
|
||||
INLINE bool type_is_arraylike(Type *type);
|
||||
@@ -2475,12 +2475,20 @@ INLINE Type *type_from_inferred(Type *flattened, Type *element_type, unsigned co
|
||||
{
|
||||
switch (flattened->type_kind)
|
||||
{
|
||||
case TYPE_POINTER:
|
||||
assert(count == 0);
|
||||
return type_get_ptr(element_type);
|
||||
case TYPE_VECTOR:
|
||||
assert(flattened->array.len == count);
|
||||
FALLTHROUGH;
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
return type_get_vector(element_type, count);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
assert(flattened->array.len == count);
|
||||
FALLTHROUGH;
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
return type_get_array(element_type, count);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -2496,6 +2504,9 @@ INLINE bool type_len_is_inferred(Type *type)
|
||||
case TYPE_TYPEDEF:
|
||||
type = type->canonical;
|
||||
continue;
|
||||
case TYPE_OPTIONAL:
|
||||
type = type->optional;
|
||||
continue;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
@@ -2833,7 +2844,7 @@ INLINE bool type_is_func_ptr(Type *fn_type)
|
||||
return fn_type->pointer->type_kind == TYPE_FUNC;
|
||||
}
|
||||
|
||||
INLINE bool type_is_len_inferred(Type *type)
|
||||
INLINE bool type_is_inferred(Type *type)
|
||||
{
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind == TYPE_INFERRED_VECTOR || kind == TYPE_INFERRED_ARRAY;
|
||||
|
||||
@@ -84,7 +84,7 @@ typedef enum
|
||||
CAST_ARRVEC,
|
||||
CAST_BOOLBOOL,
|
||||
CAST_BOOLFP,
|
||||
CAST_BOOLINT,
|
||||
CAST_BOOLXI,
|
||||
CAST_BOOLVECINT,
|
||||
CAST_BSARRY,
|
||||
CAST_BSINT,
|
||||
@@ -100,7 +100,7 @@ typedef enum
|
||||
CAST_FPFP,
|
||||
CAST_FPSI,
|
||||
CAST_FPUI,
|
||||
CAST_INTBOOL,
|
||||
CAST_XIBOOL,
|
||||
CAST_INTENUM,
|
||||
CAST_NUMVEC,
|
||||
CAST_PTRANY,
|
||||
|
||||
@@ -354,11 +354,11 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
|
||||
case CAST_XIERR:
|
||||
case CAST_STRPTR:
|
||||
case CAST_PTRBOOL:
|
||||
case CAST_BOOLINT:
|
||||
case CAST_BOOLXI:
|
||||
case CAST_BOOLFP:
|
||||
case CAST_BOOLBOOL:
|
||||
case CAST_FPBOOL:
|
||||
case CAST_INTBOOL:
|
||||
case CAST_XIBOOL:
|
||||
case CAST_FPFP:
|
||||
case CAST_FPSI:
|
||||
case CAST_FPUI:
|
||||
|
||||
@@ -1318,7 +1318,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
|
||||
value->value = LLVMBuildIsNotNull(c->builder, value->value, "ptrbool");
|
||||
value->kind = BE_BOOLEAN;
|
||||
break;
|
||||
case CAST_BOOLINT:
|
||||
case CAST_BOOLXI:
|
||||
llvm_value_rvalue(c, value);
|
||||
value->value = LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "boolsi");
|
||||
value->kind = BE_VALUE;
|
||||
@@ -1337,7 +1337,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
|
||||
value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp");
|
||||
value->kind = BE_VALUE;
|
||||
break;
|
||||
case CAST_INTBOOL:
|
||||
case CAST_XIBOOL:
|
||||
llvm_value_rvalue(c, value);
|
||||
value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool");
|
||||
value->kind = type_kind_is_any_vector(value->type->type_kind) ? BE_BOOLVECTOR : BE_BOOLEAN;
|
||||
|
||||
@@ -18,7 +18,20 @@ static Expr *recursive_may_narrow_int(Expr *expr, Type *type);
|
||||
static void recursively_rewrite_untyped_list(Expr *expr, Expr **list);
|
||||
static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee);
|
||||
static inline bool cast_may_array(Type *from, Type *to, bool is_explicit);
|
||||
static inline bool insert_cast(Expr *expr, CastKind kind, Type *type);
|
||||
static bool pointer_to_integer(Expr *expr, Type *type);
|
||||
static bool pointer_to_bool(Expr *expr, Type *type);
|
||||
static bool pointer_to_pointer(Expr* expr, Type *type);
|
||||
static bool bool_to_int(Expr *expr, Type *canonical, Type *type);
|
||||
static bool bool_to_float(Expr *expr, Type *canonical, Type *type);
|
||||
static bool integer_to_bool(Expr *expr, Type *type);
|
||||
static bool voidfail_to_error(Expr *expr, Type *type);
|
||||
static void const_int_to_fp_cast(Expr *expr, Type *canonical, Type *type);
|
||||
INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type);
|
||||
|
||||
/**
|
||||
* Insert a cast. This will assume that the cast is valid. No typeinfo will be registered.
|
||||
*/
|
||||
static inline bool insert_cast(Expr *expr, CastKind kind, Type *type)
|
||||
{
|
||||
assert(expr->resolve_status == RESOLVE_DONE);
|
||||
@@ -32,6 +45,9 @@ static inline bool insert_cast(Expr *expr, CastKind kind, Type *type)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* General error due to casts.
|
||||
*/
|
||||
bool sema_error_failed_cast(Expr *expr, Type *from, Type *to)
|
||||
{
|
||||
SEMA_ERROR(expr, "The cast %s to %s is not allowed.", type_quoted_error_string(from), type_quoted_error_string(to));
|
||||
@@ -39,45 +55,82 @@ bool sema_error_failed_cast(Expr *expr, Type *from, Type *to)
|
||||
}
|
||||
|
||||
|
||||
Type *cast_infer_len(Type *to_infer, Type *actual_type)
|
||||
/**
|
||||
* Create a type by inferring the length.
|
||||
*/
|
||||
Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type)
|
||||
{
|
||||
Type *may_infer = to_infer->canonical;
|
||||
Type *actual = actual_type->canonical;
|
||||
if (may_infer == actual) return to_infer;
|
||||
bool canonical_same_kind = may_infer->type_kind == to_infer->type_kind;
|
||||
assert(type_is_arraylike(actual_type));
|
||||
if (may_infer->type_kind == TYPE_INFERRED_ARRAY)
|
||||
// This may be called on types not inferrable,
|
||||
// if so we assume the original type
|
||||
if (!type_len_is_inferred(to_infer)) return to_infer;
|
||||
|
||||
// Handle int[*]! a = { ... } by stripping the optional.
|
||||
bool is_optional = type_is_optional(to_infer);
|
||||
|
||||
assert(is_optional || !type_is_optional(actual_type) && "int[*] x = { may_fail } should have been caught.");
|
||||
|
||||
// Strip the optional
|
||||
if (is_optional) to_infer = to_infer->optional;
|
||||
|
||||
// And from the actual type.
|
||||
actual_type = type_no_optional(actual_type);
|
||||
|
||||
// Grab the underlying indexed type,
|
||||
// because we can only have [*] [] [<*>] [<>] * here
|
||||
Type *indexed = type_get_indexed_type(to_infer);
|
||||
Type *actual = type_get_indexed_type(actual_type);
|
||||
|
||||
// We should always have indexed types.
|
||||
assert(indexed && actual);
|
||||
|
||||
// The underlying type may also be inferred.
|
||||
// In this case, infer it.
|
||||
if (type_len_is_inferred(indexed))
|
||||
{
|
||||
Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base :
|
||||
may_infer->array.base, actual->array.base);
|
||||
return type_get_array(base_type, actual->array.len);
|
||||
// if we have int[*][*] => the inner is int[*], we cast it here.
|
||||
indexed = type_infer_len_from_actual_type(indexed, actual);
|
||||
}
|
||||
if (may_infer->type_kind == TYPE_INFERRED_VECTOR)
|
||||
|
||||
// Construct the real type
|
||||
switch (to_infer->type_kind)
|
||||
{
|
||||
Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : may_infer->array.base, actual->array.base);
|
||||
if (actual_type->type_kind == TYPE_SCALED_VECTOR)
|
||||
{
|
||||
return type_get_scaled_vector(base_type);
|
||||
}
|
||||
return type_get_vector(base_type, actual->array.len);
|
||||
case TYPE_POINTER:
|
||||
// The case of int[*]* x = ...
|
||||
return type_add_optional(type_get_ptr(indexed), is_optional);
|
||||
case TYPE_ARRAY:
|
||||
// The case of int[*][2] x = ...
|
||||
return type_add_optional(type_get_array(indexed, to_infer->array.len), is_optional);
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
assert(type_is_arraylike(type_flatten(actual_type)));
|
||||
return type_add_optional(type_get_array(indexed, type_flatten(actual_type)->array.len), is_optional);
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
assert(type_is_arraylike(type_flatten(actual_type)));
|
||||
return type_add_optional(type_get_vector(indexed, type_flatten(actual_type)->array.len), is_optional);
|
||||
case TYPE_VECTOR:
|
||||
// This is unreachable, because unlike arrays, there is no inner type that may be
|
||||
// the inferred part.
|
||||
UNREACHABLE
|
||||
case TYPE_SUBARRAY:
|
||||
// The case of int[*][] y = ... is disallowed
|
||||
UNREACHABLE
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (may_infer->type_kind == TYPE_POINTER)
|
||||
{
|
||||
assert(actual->type_kind == TYPE_POINTER);
|
||||
Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : may_infer->pointer, actual->pointer);
|
||||
return type_get_ptr(base_type);
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static inline bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type)
|
||||
/**
|
||||
* Insert a cast on non-const only
|
||||
*/
|
||||
INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type)
|
||||
{
|
||||
if (expr->expr_kind == EXPR_CONST) return false;
|
||||
return insert_cast(expr, kind, type);
|
||||
}
|
||||
|
||||
|
||||
bool pointer_to_integer(Expr *expr, Type *type)
|
||||
/**
|
||||
* Insert the PTRXI cast, or on const do a rewrite.
|
||||
*/
|
||||
static bool pointer_to_integer(Expr *expr, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_PTRXI, type)) return true;
|
||||
|
||||
@@ -86,37 +139,49 @@ bool pointer_to_integer(Expr *expr, Type *type)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pointer_to_bool(Expr *expr, Type *type)
|
||||
/**
|
||||
* Insert the PTRBOOL cast or on const do a rewrite.
|
||||
*/
|
||||
static bool pointer_to_bool(Expr *expr, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return true;
|
||||
|
||||
// It may be a pointer
|
||||
if (expr->const_expr.const_kind == CONST_POINTER)
|
||||
{
|
||||
expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Or it's a string, in which case it is always true.
|
||||
assert(expr->const_expr.const_kind == CONST_STRING);
|
||||
expr_rewrite_const_bool(expr, type, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool pointer_to_pointer(Expr* expr, Type *type)
|
||||
/**
|
||||
* Insert a PTRPTR cast or update the pointer type
|
||||
*/
|
||||
static bool pointer_to_pointer(Expr* expr, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_PTRPTR, type)) return true;
|
||||
|
||||
// Strings cannot be compile-time folded, so insert a runtime cast.
|
||||
if (expr->const_expr.const_kind == CONST_STRING)
|
||||
{
|
||||
return insert_cast(expr, CAST_PTRPTR, type);
|
||||
}
|
||||
// Must have been a null
|
||||
|
||||
// Insert the cast, this removes the ability to narrow it.
|
||||
expr->type = type;
|
||||
expr->const_expr.narrowable = false;
|
||||
expr->const_expr.is_hex = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do a const int -> float cast.
|
||||
*/
|
||||
static void const_int_to_fp_cast(Expr *expr, Type *canonical, Type *type)
|
||||
{
|
||||
Real f = int_to_real(expr->const_expr.ixx);
|
||||
@@ -129,9 +194,11 @@ static void const_int_to_fp_cast(Expr *expr, Type *canonical, Type *type)
|
||||
expr->const_expr.fxx = (Float) { (double)f, TYPE_F64 };
|
||||
break;
|
||||
default:
|
||||
REMINDER("Int to fp cast may be too wide.");
|
||||
expr->const_expr.fxx = (Float) { f, canonical->type_kind };
|
||||
break;
|
||||
}
|
||||
// It's not allowed to narrow after a cast.
|
||||
expr->type = type;
|
||||
expr->const_expr.const_kind = CONST_FLOAT;
|
||||
expr->const_expr.narrowable = false;
|
||||
@@ -140,20 +207,23 @@ static void const_int_to_fp_cast(Expr *expr, Type *canonical, Type *type)
|
||||
|
||||
|
||||
/**
|
||||
* Bool into a signed or unsigned int.
|
||||
* Bool into a signed or unsigned int using CAST_BOOLXI
|
||||
* or rewrite to 0 / 1 for false / true.
|
||||
*/
|
||||
bool bool_to_int(Expr *expr, Type *canonical, Type *type)
|
||||
static bool bool_to_int(Expr *expr, Type *canonical, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_BOOLINT, type)) return true;
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_BOOLXI, type)) return true;
|
||||
|
||||
expr_rewrite_const_int(expr, type, expr->const_expr.b ? 1 : 0, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cast bool to float.
|
||||
* Cast bool to float using CAST_BOOLFP
|
||||
* or rewrite to 0.0 / 1.0 for false / true
|
||||
*/
|
||||
bool bool_to_float(Expr *expr, Type *canonical, Type *type)
|
||||
static bool bool_to_float(Expr *expr, Type *canonical, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_BOOLFP, type)) return true;
|
||||
|
||||
@@ -163,10 +233,12 @@ bool bool_to_float(Expr *expr, Type *canonical, Type *type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast bool to float.
|
||||
* Insert a cast from `void!` to some fault type by inserting a `catch`,
|
||||
* so "anyerr a = returns_voidfail()" => "anyerr a = catch(returns_voidfail())"
|
||||
*/
|
||||
bool voidfail_to_error(Expr *expr, Type *type)
|
||||
static bool voidfail_to_error(Expr *expr, Type *type)
|
||||
{
|
||||
assert(type->canonical->type_kind == TYPE_FAULTTYPE || type == type_anyerr);
|
||||
Expr *inner = expr_copy(expr);
|
||||
expr->expr_kind = EXPR_CATCH;
|
||||
expr->inner_expr = inner;
|
||||
@@ -175,19 +247,20 @@ bool voidfail_to_error(Expr *expr, Type *type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from any into to bool.
|
||||
* @return true for any implicit conversion except assign and assign add.
|
||||
* Cast int to bool using CAST_XIBOOL
|
||||
* or rewrite 0 => false, any other value => true
|
||||
*/
|
||||
bool integer_to_bool(Expr *expr, Type *type)
|
||||
static bool integer_to_bool(Expr *expr, Type *type)
|
||||
{
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_INTBOOL, type)) return true;
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_XIBOOL, type)) return true;
|
||||
|
||||
expr_rewrite_const_bool(expr, type, !int_is_zero(expr->const_expr.ixx));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from any float to bool
|
||||
* Cast any float to bool using CAST_FPBOOL
|
||||
* or rewrite 0.0 => false, any other value => true
|
||||
*/
|
||||
bool float_to_bool(Expr *expr, Type *type)
|
||||
{
|
||||
@@ -199,11 +272,17 @@ bool float_to_bool(Expr *expr, Type *type)
|
||||
|
||||
|
||||
/**
|
||||
* Convert from any fp to fp
|
||||
* Convert any fp to another fp type using CAST_FPFP
|
||||
*/
|
||||
static bool float_to_float(Expr* expr, Type *canonical, Type *type)
|
||||
{
|
||||
// Change to same type should never enter here.
|
||||
assert(type_flatten(canonical) != type_flatten(expr->type));
|
||||
|
||||
// Insert runtime cast if needed.
|
||||
if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return true;
|
||||
|
||||
// Otherwise rewrite the const, which may cause rounding.
|
||||
expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f);
|
||||
return true;
|
||||
}
|
||||
@@ -431,7 +510,7 @@ CastKind cast_to_bool_kind(Type *type)
|
||||
case TYPE_SUBARRAY:
|
||||
return CAST_SABOOL;
|
||||
case ALL_INTS:
|
||||
return CAST_INTBOOL;
|
||||
return CAST_XIBOOL;
|
||||
case ALL_FLOATS:
|
||||
return CAST_FPBOOL;
|
||||
case TYPE_POINTER:
|
||||
@@ -1132,7 +1211,7 @@ CAST_ELEMENT:
|
||||
CAST:
|
||||
if (infer_type)
|
||||
{
|
||||
to_type = cast_infer_len(to_type, from);
|
||||
to_type = type_infer_len_from_actual_type(to_type, from);
|
||||
}
|
||||
return cast_with_optional(expr, to_type, add_optional);
|
||||
CAST_ILLEGAL:
|
||||
@@ -1228,7 +1307,7 @@ TRY_CAST:
|
||||
CAST_ILLEGAL:
|
||||
return sema_error_cannot_convert(expr, to_type, false, silent);
|
||||
CAST:
|
||||
if (infer_len) to_type = cast_infer_len(to_type, from);
|
||||
if (infer_len) to_type = type_infer_len_from_actual_type(to_type, from);
|
||||
return cast_with_optional(expr, to_type, add_optional);
|
||||
}
|
||||
|
||||
@@ -1763,14 +1842,14 @@ static bool vec_to_vec(Expr *expr, Type *to_type)
|
||||
}
|
||||
if (type_is_signed(from_element))
|
||||
{
|
||||
if (to_element == type_bool) return insert_cast(expr, CAST_INTBOOL, to_type);
|
||||
if (to_element == type_bool) return insert_cast(expr, CAST_XIBOOL, to_type);
|
||||
if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_SIUI, to_type);
|
||||
if (type_is_signed(to_element)) return insert_cast(expr, CAST_SISI, to_type);
|
||||
if (type_is_float(to_element)) return insert_cast(expr, CAST_SIFP, to_type);
|
||||
UNREACHABLE
|
||||
}
|
||||
assert(type_is_unsigned(from_element));
|
||||
if (to_element == type_bool) return insert_cast(expr, CAST_INTBOOL, to_type);
|
||||
if (to_element == type_bool) return insert_cast(expr, CAST_XIBOOL, to_type);
|
||||
if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_UIUI, to_type);
|
||||
if (type_is_signed(to_element)) return insert_cast(expr, CAST_UISI, to_type);
|
||||
if (type_is_float(to_element)) return insert_cast(expr, CAST_UIFP, to_type);
|
||||
|
||||
@@ -2760,12 +2760,12 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
||||
|
||||
if (infer_len)
|
||||
{
|
||||
if (type_is_len_inferred(init->type))
|
||||
if (type_is_inferred(init->type))
|
||||
{
|
||||
SEMA_ERROR(decl->var.type_info, "You cannot use [*] and [<*>] underlying types with initializers.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
decl->type = cast_infer_len(decl->type, init->type);
|
||||
decl->type = type_infer_len_from_actual_type(decl->type, init->type);
|
||||
}
|
||||
|
||||
Expr *init_expr = decl->var.init_expr;
|
||||
|
||||
@@ -251,6 +251,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
|
||||
|
||||
bool optional = false;
|
||||
bool is_vector = type_flat_is_vector(assigned);
|
||||
bool inner_is_inferred = type_len_is_inferred(inner_type);
|
||||
Type *inferred_element = NULL;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
Expr *element = elements[i];
|
||||
@@ -302,9 +304,34 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr_rhs(context, inner_type, element, true)) return false;
|
||||
if (inner_is_inferred)
|
||||
{
|
||||
Type *element_type = type_no_optional(element->type);
|
||||
if (inferred_element)
|
||||
{
|
||||
if (!cast_implicit(context, element, inferred_element))
|
||||
{
|
||||
SEMA_NOTE(elements[0], "Type inferred from here.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inferred_element = type_infer_len_from_actual_type(inner_type, element_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
optional = optional || IS_OPTIONAL(element);
|
||||
}
|
||||
if (inner_is_inferred)
|
||||
{
|
||||
if (!inferred_element)
|
||||
{
|
||||
SEMA_ERROR(initializer, "Zero sized elements are not allowed when inferring size.");
|
||||
return false;
|
||||
}
|
||||
inner_type = inferred_element;
|
||||
}
|
||||
if (inferred_len)
|
||||
{
|
||||
initializer->type = type_from_inferred(flattened, inner_type, count);
|
||||
@@ -377,7 +404,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
|
||||
MemberIndex max_index = -1;
|
||||
bool optional = false;
|
||||
Type *inner_type = NULL;
|
||||
bool is_inferred = type_is_len_inferred(flattened);
|
||||
bool is_inferred = type_is_inferred(flattened);
|
||||
VECEACH(init_expressions, i)
|
||||
{
|
||||
Expr *expr = init_expressions[i];
|
||||
@@ -423,11 +450,6 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass
|
||||
// EXPR_DESIGNATED_INITIALIZER_LIST
|
||||
// or EXPR_INITIALIZER_LIST
|
||||
|
||||
if (type_len_is_inferred(flattened) && type_len_is_inferred(type_get_indexed_type(flattened)))
|
||||
{
|
||||
SEMA_ERROR(expr, "Initializers cannot be used with inferred length element types (e.g. %s).", type_quoted_error_string(type_get_indexed_type(flattened)));
|
||||
return false;
|
||||
}
|
||||
// 1. Designated initializer is separately evaluated.
|
||||
if (expr->expr_kind == EXPR_DESIGNATED_INITIALIZER_LIST)
|
||||
{
|
||||
|
||||
17
test/test_suite/arrays/complex_inferred_array.c3t
Normal file
17
test/test_suite/arrays/complex_inferred_array.c3t
Normal file
@@ -0,0 +1,17 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
int[*][*][2][*]! y = { {{{1}, {2}}, { {3}, {4}}}};
|
||||
int[*][*][2][*] x = { {{{1}, {2}}, { {3}, {4}}}};
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
@.__const = private unnamed_addr constant [1 x [2 x [2 x [1 x i32]]]] [[2 x [2 x [1 x i32]]] [[2 x [1 x i32]] [[1 x i32] [i32 1], [1 x i32] [i32 2]], [2 x [1 x i32]] [[1 x i32] [i32 3], [1 x i32] [i32 4]]]], align 16
|
||||
@.__const.1 = private unnamed_addr constant [1 x [2 x [2 x [1 x i32]]]] [[2 x [2 x [1 x i32]]] [[2 x [1 x i32]] [[1 x i32] [i32 1], [1 x i32] [i32 2]], [2 x [1 x i32]] [[1 x i32] [i32 3], [1 x i32] [i32 4]]]], align 16
|
||||
|
||||
%y = alloca [1 x [2 x [2 x [1 x i32]]]], align 16
|
||||
%x = alloca [1 x [2 x [2 x [1 x i32]]]], align 16
|
||||
92
test/test_suite/arrays/inferred_array_optional.c3t
Normal file
92
test/test_suite/arrays/inferred_array_optional.c3t
Normal file
@@ -0,0 +1,92 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
|
||||
fn int! foo() => 1;
|
||||
|
||||
fn int main()
|
||||
{
|
||||
int[*]! x = { 1, 2 };
|
||||
int[*]! y = { foo(), foo() };
|
||||
int[<*>]! x2 = { 1, 2 };
|
||||
int[<*>]! y2 = { foo(), foo() };
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%x = alloca [2 x i32], align 4
|
||||
%x.f = alloca i64, align 8
|
||||
%y = alloca [2 x i32], align 4
|
||||
%y.f = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%retparam1 = alloca i32, align 4
|
||||
%x2 = alloca <2 x i32>, align 8
|
||||
%x2.f = alloca i64, align 8
|
||||
%y2 = alloca <2 x i32>, align 8
|
||||
%y2.f = alloca i64, align 8
|
||||
%retparam5 = alloca i32, align 4
|
||||
%retparam9 = alloca i32, align 4
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4
|
||||
store i64 0, ptr %x.f, align 8
|
||||
%0 = getelementptr inbounds [2 x i32], ptr %y, i64 0, i64 0
|
||||
%1 = call i64 @test.foo(ptr %retparam)
|
||||
%not_err = icmp eq i64 %1, 0
|
||||
%2 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %2, label %after_check, label %assign_optional
|
||||
|
||||
assign_optional: ; preds = %entry
|
||||
store i64 %1, ptr %y.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%3 = load i32, ptr %retparam, align 4
|
||||
store i32 %3, ptr %0, align 4
|
||||
%4 = getelementptr inbounds [2 x i32], ptr %y, i64 0, i64 1
|
||||
%5 = call i64 @test.foo(ptr %retparam1)
|
||||
%not_err2 = icmp eq i64 %5, 0
|
||||
%6 = call i1 @llvm.expect.i1(i1 %not_err2, i1 true)
|
||||
br i1 %6, label %after_check4, label %assign_optional3
|
||||
|
||||
assign_optional3: ; preds = %after_check
|
||||
store i64 %5, ptr %y.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_check4: ; preds = %after_check
|
||||
%7 = load i32, ptr %retparam1, align 4
|
||||
store i32 %7, ptr %4, align 4
|
||||
store i64 0, ptr %y.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_assign: ; preds = %after_check4, %assign_optional3, %assign_optional
|
||||
store <2 x i32> <i32 1, i32 2>, ptr %x2, align 8
|
||||
store i64 0, ptr %x2.f, align 8
|
||||
%8 = call i64 @test.foo(ptr %retparam5)
|
||||
%not_err6 = icmp eq i64 %8, 0
|
||||
%9 = call i1 @llvm.expect.i1(i1 %not_err6, i1 true)
|
||||
br i1 %9, label %after_check8, label %assign_optional7
|
||||
|
||||
assign_optional7: ; preds = %after_assign
|
||||
store i64 %8, ptr %y2.f, align 8
|
||||
br label %after_assign13
|
||||
|
||||
after_check8: ; preds = %after_assign
|
||||
%10 = load i32, ptr %retparam5, align 4
|
||||
%11 = insertelement <2 x i32> undef, i32 %10, i64 0
|
||||
%12 = call i64 @test.foo(ptr %retparam9)
|
||||
%not_err10 = icmp eq i64 %12, 0
|
||||
%13 = call i1 @llvm.expect.i1(i1 %not_err10, i1 true)
|
||||
br i1 %13, label %after_check12, label %assign_optional11
|
||||
|
||||
assign_optional11: ; preds = %after_check8
|
||||
store i64 %12, ptr %y2.f, align 8
|
||||
br label %after_assign13
|
||||
|
||||
after_check12: ; preds = %after_check8
|
||||
%14 = load i32, ptr %retparam9, align 4
|
||||
%15 = insertelement <2 x i32> %11, i32 %14, i64 1
|
||||
store <2 x i32> %15, ptr %y2, align 8
|
||||
store i64 0, ptr %y2.f, align 8
|
||||
br label %after_assign13
|
||||
Reference in New Issue
Block a user