Cleanup of untyped lists.

This commit is contained in:
Christoffer Lerno
2022-09-23 10:40:13 +02:00
committed by Christoffer Lerno
parent 46c182f3d1
commit 52f3948026
8 changed files with 69 additions and 55 deletions

View File

@@ -1763,7 +1763,7 @@ extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff;
extern Type *type_u128, *type_i128;
extern Type *type_typeid, *type_anyerr, *type_typeinfo;
extern Type *type_any;
extern Type *type_complist;
extern Type *type_untypedlist;
extern Type *type_anyfail;
extern Type *type_cint;
extern Type *type_cuint;

View File

@@ -2092,7 +2092,7 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
SEMA_ERROR(first_param, "The first parameter must be a regular or ref (&) type.");
return false;
}
return unit_add_method_like(context->unit, parent_type, decl);
return unit_add_method_like(context->unit, parent_type->canonical, decl);
}
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)

View File

@@ -1021,6 +1021,11 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
else if (variadic == VARIADIC_ANY)
{
if (!sema_analyse_expr(context, arg)) return false;
if (arg->type == type_untypedlist)
{
SEMA_ERROR(arg, "An untyped list cannot be passed as a variadic argument.");
return false;
}
expr_insert_addr(arg);
}
vec_add(*varargs_ref, arg);
@@ -1276,6 +1281,11 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
if (!sema_analyse_expr_lvalue(context, arg)) return false;
if (!sema_expr_check_assign(context, arg)) return false;
if (!sema_call_check_inout_param_match(context, param, arg)) return false;
if (arg->type == type_untypedlist)
{
SEMA_ERROR(arg, "An untyped list cannot be passed by reference.");
return false;
}
if (type && type->canonical != arg->type->canonical)
{
SEMA_ERROR(arg, "'%s' cannot be implicitly cast to '%s'.", type_to_error_string(arg->type), type_to_error_string(type));
@@ -1297,7 +1307,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
// foo
if (!sema_analyse_expr_rhs(context, type, arg, true)) return false;
if (IS_OPTIONAL(arg)) *failable = true;
if (arg->type == type_complist)
if (arg->type == type_untypedlist)
{
SEMA_ERROR(arg, "An untyped list can only be passed as a compile time parameter.");
return false;
@@ -2171,7 +2181,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
int64_t index_value = -1;
bool start_from_end = expr->subscript_expr.range.start_from_end;
if (expr_is_const_int(index) && (current_type->type_kind == TYPE_ARRAY || current_type == type_complist))
if (expr_is_const_int(index) && (current_type->type_kind == TYPE_ARRAY || current_type == type_untypedlist))
{
// 4c. And that it's in range.
if (int_is_neg(index->const_expr.ixx))
@@ -2179,9 +2189,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
SEMA_ERROR(index, "The index may not be negative.");
return false;
}
int64_t size = current_type == type_complist ? vec_size(current_expr->initializer_list) : current_type->array.len;
int64_t size = current_type == type_untypedlist ? vec_size(current_expr->const_expr.list->init_array_full) : current_type->array.len;
assert(size >= 0 && "Unexpected overflow");
if (!int_fits(index->const_expr.ixx, TYPE_I64))
if (!int_fits(index->const_expr.ixx, TYPE_I64) || size == 0)
{
SEMA_ERROR(index, "The index is out of range.", size);
return false;
@@ -2215,7 +2225,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
}
}
// 4. If we are indexing into a complist
if (current_type == type_complist)
if (current_type == type_untypedlist)
{
if (is_addr)
{
@@ -2225,7 +2235,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
// 4a. This may either be an initializer list or a CT value
while (current_expr->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
assert(current_expr->expr_kind == EXPR_INITIALIZER_LIST);
assert(expr_is_const_list(current_expr));
// 4b. Now we need to check that we actually have a valid type.
if (index_value < 0)
@@ -2233,10 +2243,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
SEMA_ERROR(index, "To subscript a compile time list a compile time integer index is needed.");
return false;
}
Expr *indexed_expr = current_expr->initializer_list[index_value];
if (!sema_cast_rvalue(context, indexed_expr)) return false;
expr_replace(expr, indexed_expr);
return true;
return expr_rewrite_to_const_initializer_index(type_untypedlist, current_expr->const_expr.list, expr, index_value);
}
if (!sema_cast_rvalue(context, current_expr)) return false;
@@ -3487,7 +3494,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr)
SEMA_ERROR(type_info, "Casting to a failable type is not allowed.");
return false;
}
if (inner->type == type_complist)
if (inner->type == type_untypedlist)
{
// We don't support: (Foo)(x > 0 ? { 1, 2 } : { 3, 4 })
// just write this: x > 0 ? Foo { 1, 2 } : Foo { 3, 4 }
@@ -5110,6 +5117,11 @@ static inline bool sema_expr_analyse_taddr(SemaContext *context, Expr *expr)
Expr *inner = expr->unary_expr.expr;
if (!sema_analyse_expr(context, inner)) return false;
if (inner->type == type_untypedlist)
{
SEMA_ERROR(expr, "It is not possible to take the address of an untyped list.");
return false;
}
// 2. The type is the resulting type of the expression.
expr->type = type_get_ptr_recurse(inner->type);
return true;
@@ -6448,7 +6460,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
return sema_expr_analyse_access(context, expr);
case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST:
return sema_expr_analyse_initializer_list(context, type_complist, expr);
return sema_expr_analyse_initializer_list(context, type_untypedlist, expr);
case EXPR_CAST:
return sema_expr_analyse_cast(context, expr);
case EXPR_EXPRESSION_LIST:

View File

@@ -11,7 +11,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
static inline void sema_not_enough_elements_error(Expr *initializer, int element);
static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *external_type, Type *assigned, Expr *expr);
static void sema_create_const_initializer_value(ConstInitializer *const_init, Expr *value);
static void sema_create_const_initializer(ConstInitializer *const_init, Expr *initializer);
static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer);
static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **elements, unsigned *index);
static Type *sema_expr_analyse_designator(SemaContext *context, Type *current, Expr *expr, MemberIndex *max_index, Decl **member_ptr);
INLINE bool sema_initializer_list_is_empty(Expr *value);
@@ -282,40 +282,30 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer)
{
Expr **elements = initializer->initializer_list;
Type *element_type = NULL;
bool no_common_elements = false;
unsigned element_count = vec_size(elements);
bool is_const = true;
Expr *failable_expr = NULL;
for (unsigned i = 0; i < element_count; i++)
{
Expr *element = elements[i];
ConstInitializer **inits = NULL;
FOREACH_BEGIN(Expr *element, initializer->initializer_list)
if (!sema_analyse_expr(context, element)) return false;
if (is_const && element->expr_kind != EXPR_CONST) is_const = false;
if (!failable_expr && IS_OPTIONAL(element)) failable_expr = element;
if (no_common_elements) continue;
Type *current_element_type = type_no_optional(element->type);
if (element_type == NULL)
if (!expr_is_const(element))
{
element_type = element->type;
continue;
SEMA_ERROR(element, "An untyped list can only have constant elements, you can try to type the list by prefixing the type, e.g. 'int[2] { a, b }'.");
return false;
}
element_type = type_find_max_type(element->type, current_element_type);
if (!element_type) no_common_elements = true;
}
if (no_common_elements && failable_expr)
ConstInitializer *init = CALLOCS(ConstInitializer);
sema_create_const_initializer_value(init, element);
vec_add(inits, init);
FOREACH_END();
ConstInitializer *untyped_list = CALLOCS(ConstInitializer);
initializer->expr_kind = EXPR_CONST;
initializer->const_expr = (ExprConst) { .const_kind = CONST_LIST, .list = untyped_list };
untyped_list->type = type_untypedlist;
initializer->type = type_untypedlist;
if (!inits)
{
SEMA_ERROR(failable_expr, "An untyped initializer can't have failable values.");
return false;
}
if (no_common_elements || is_const)
{
initializer->type = type_complist;
untyped_list->kind = CONST_INIT_ZERO;
return true;
}
initializer->type = type_add_optional(type_get_array(element_type, element_count), failable_expr != NULL);
untyped_list->kind = CONST_INIT_ARRAY_FULL;
untyped_list->init_array_full = inits;
return true;
}
@@ -351,7 +341,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
if (expr_is_constant_eval(initializer, context->current_function ? CONSTANT_EVAL_LOCAL_INIT : CONSTANT_EVAL_GLOBAL_INIT))
{
ConstInitializer *const_init = MALLOCS(ConstInitializer);
sema_create_const_initializer(const_init, initializer);
sema_create_const_initializer_from_designated_init(const_init, initializer);
expr_rewrite_const_list(initializer, initializer->type, const_init);
}
return true;
@@ -408,7 +398,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
expr->type = external_type;
// 6. We might have a complist, because were analyzing $foo = { ... } or similar.
if (external_type == type_complist)
if (external_type == type_untypedlist)
{
return sema_expr_analyse_untyped_initializer(context, expr);
}
@@ -429,7 +419,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
/**
* Create a const initializer.
*/
static void sema_create_const_initializer(ConstInitializer *const_init, Expr *initializer)
static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer)
{
const_init->kind = CONST_INIT_ZERO;
// Flatten the type since the external type might be typedef or a distinct type.
@@ -448,7 +438,7 @@ static void sema_create_const_initializer(ConstInitializer *const_init, Expr *in
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr)
{
if (!to) to = type_complist;
if (!to) to = type_untypedlist;
assert(to);
Type *assigned = type_flatten(to);
switch (assigned->type_kind)

View File

@@ -10,7 +10,7 @@ static struct
Type u8, u16, u32, u64, u128;
Type f16, f32, f64, f128, fxx;
Type usz, isz, uptr, iptr, uptrdiff, iptrdiff;
Type voidstar, typeid, anyerr, typeinfo, ctlist;
Type voidstar, typeid, anyerr, typeinfo, untyped_list;
Type any, anyfail;
} t;
@@ -41,7 +41,7 @@ Type *type_uptr = &t.uptr;
Type *type_uptrdiff = &t.uptrdiff;
Type *type_usize = &t.usz;
Type *type_anyerr = &t.anyerr;
Type *type_complist = &t.ctlist;
Type *type_untypedlist = &t.untyped_list;
Type *type_anyfail = &t.anyfail;
Type *type_chars = NULL;
@@ -1351,7 +1351,7 @@ void type_setup(PlatformTarget *target)
type_init_int("void", &t.u0, TYPE_VOID, BITS8);
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1);
type_create("untyped_list", &t.untyped_list, TYPE_UNTYPED_LIST, 1, 1, 1);
type_create("void!", &t.anyfail, TYPE_FAILABLE_ANY, 1, 1, 1);
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.3.55"
#define COMPILER_VERSION "0.3.56"

View File

@@ -11,10 +11,16 @@ fault MyErr
extern fn int printf(char *c, ...);
fn void main()
fn void foo()
{
int z = 2;
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
}
fn void foo2()
{
int! z = 2;
Foo*! w = &&{ z, 0 }; // #error: A failable 'int[2]*!' cannot be converted to 'Foo*'
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
}
fn void test()

View File

@@ -11,10 +11,16 @@ fault MyErr
extern fn int printf(char *c, ...);
fn void main()
fn void foo()
{
int z = 2;
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
}
fn void foo2()
{
int! z = 2;
Foo*! w = &&{ z, 0 }; // #error: A failable 'int[2]*!' cannot be converted to 'Foo*'
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
}
fn void test()