mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 09:54:45 +00:00
Merge branch 'master' into new-temp-allocator
This commit is contained in:
@@ -1679,9 +1679,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
|
||||
case Token_Not:
|
||||
if (!is_type_boolean(type)) {
|
||||
ERROR_BLOCK();
|
||||
str = expr_to_string(o->expr);
|
||||
error(op, "Operator '%.*s' is only allowed on boolean expression", LIT(op.string));
|
||||
error(op, "Operator '%.*s' is only allowed on boolean expressions", LIT(op.string));
|
||||
gb_string_free(str);
|
||||
if (is_type_integer(type)) {
|
||||
error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2019,6 +2023,47 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type) {
|
||||
if (is_type_integer(type) && o->value.kind == ExactValue_Integer) {
|
||||
gbString b = type_to_string(type);
|
||||
|
||||
i64 sz = type_size_of(type);
|
||||
BigInt *bi = &o->value.value_integer;
|
||||
if (is_type_unsigned(type)) {
|
||||
if (big_int_is_neg(bi)) {
|
||||
error_line("\tA negative value cannot be represented by the unsigned integer type '%s'\n", b);
|
||||
} else {
|
||||
BigInt one = big_int_make_u64(1);
|
||||
BigInt max_size = big_int_make_u64(1);
|
||||
BigInt bits = big_int_make_i64(8*sz);
|
||||
big_int_shl_eq(&max_size, &bits);
|
||||
big_int_sub_eq(&max_size, &one);
|
||||
String max_size_str = big_int_to_string(temporary_allocator(), &max_size);
|
||||
error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str));
|
||||
}
|
||||
} else {
|
||||
BigInt zero = big_int_make_u64(0);
|
||||
BigInt one = big_int_make_u64(1);
|
||||
BigInt max_size = big_int_make_u64(1);
|
||||
BigInt bits = big_int_make_i64(8*sz - 1);
|
||||
big_int_shl_eq(&max_size, &bits);
|
||||
if (big_int_is_neg(bi)) {
|
||||
big_int_neg(&max_size, &max_size);
|
||||
String max_size_str = big_int_to_string(temporary_allocator(), &max_size);
|
||||
error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str));
|
||||
} else {
|
||||
big_int_sub_eq(&max_size, &one);
|
||||
String max_size_str = big_int_to_string(temporary_allocator(), &max_size);
|
||||
error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str));
|
||||
}
|
||||
}
|
||||
|
||||
gb_string_free(b);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) {
|
||||
gbString a = expr_to_string(o->expr);
|
||||
gbString b = type_to_string(type);
|
||||
@@ -2050,6 +2095,8 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o
|
||||
error_line("\t whereas slices in general are assumed to be mutable.\n");
|
||||
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) {
|
||||
error_line("\tSuggestion: the expression may be casted to %s\n", b);
|
||||
} else if (check_integer_exceed_suggestion(c, o, type)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2089,8 +2136,8 @@ gb_internal void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type
|
||||
}
|
||||
} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
|
||||
error_line("\tSuggestion: a string may be transmuted to %s\n", b);
|
||||
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) {
|
||||
error_line("\tSuggestion: the expression may be casted to %s\n", b);
|
||||
} else if (check_integer_exceed_suggestion(c, o, type)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2116,16 +2163,22 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ
|
||||
o->mode = Addressing_Invalid;
|
||||
);
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
|
||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
||||
} else {
|
||||
ERROR_BLOCK();
|
||||
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s);
|
||||
if (are_types_identical(o->type, type)) {
|
||||
error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b);
|
||||
} else {
|
||||
error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c);
|
||||
}
|
||||
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
} else {
|
||||
ERROR_BLOCK();
|
||||
error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s);
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
@@ -2344,7 +2397,7 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t
|
||||
}
|
||||
|
||||
|
||||
gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
|
||||
gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Operand *y, TokenKind op) {
|
||||
if (x->mode == Addressing_Type && y->mode == Addressing_Type) {
|
||||
bool comp = are_types_identical(x->type, y->type);
|
||||
switch (op) {
|
||||
@@ -2432,7 +2485,7 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok
|
||||
}
|
||||
|
||||
if (err_str != nullptr) {
|
||||
error(x->expr, "Cannot compare expression, %s", err_str);
|
||||
error(node, "Cannot compare expression, %s", err_str);
|
||||
x->type = t_untyped_bool;
|
||||
} else {
|
||||
if (x->mode == Addressing_Constant &&
|
||||
@@ -2597,10 +2650,12 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
|
||||
x->type = t_untyped_integer;
|
||||
}
|
||||
|
||||
x->expr = node;
|
||||
x->value = exact_value_shift(be->op.kind, x_val, y_val);
|
||||
|
||||
|
||||
if (is_type_typed(x->type)) {
|
||||
check_is_expressible(c, x, base_type(x->type));
|
||||
check_is_expressible(c, x, x->type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -2915,17 +2970,38 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
bool can_convert = check_cast_internal(c, x, type);
|
||||
|
||||
if (!can_convert) {
|
||||
gbString expr_str = expr_to_string(x->expr);
|
||||
gbString to_type = type_to_string(type);
|
||||
gbString from_type = type_to_string(x->type);
|
||||
error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type);
|
||||
gb_string_free(from_type);
|
||||
gb_string_free(to_type);
|
||||
gb_string_free(expr_str);
|
||||
|
||||
check_cast_error_suggestion(c, x, type);
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
gbString expr_str = expr_to_string(x->expr, temporary_allocator());
|
||||
gbString to_type = type_to_string(type, temporary_allocator());
|
||||
gbString from_type = type_to_string(x->type, temporary_allocator());
|
||||
|
||||
x->mode = Addressing_Invalid;
|
||||
|
||||
begin_error_block();
|
||||
error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type);
|
||||
if (is_const_expr) {
|
||||
gbString val_str = exact_value_to_string(x->value);
|
||||
if (is_type_float(x->type) && is_type_integer(type)) {
|
||||
error_line("\t%s cannot be represented without truncation/rounding as the type '%s'\n", val_str, to_type);
|
||||
|
||||
// NOTE(bill): keep the mode and modify the type to minimize errors further on
|
||||
x->mode = Addressing_Constant;
|
||||
x->type = type;
|
||||
} else {
|
||||
error_line("\t'%s' cannot be represented as the type '%s'\n", val_str, to_type);
|
||||
if (is_type_numeric(type)) {
|
||||
// NOTE(bill): keep the mode and modify the type to minimize errors further on
|
||||
x->mode = Addressing_Constant;
|
||||
x->type = type;
|
||||
}
|
||||
}
|
||||
gb_string_free(val_str);
|
||||
|
||||
}
|
||||
check_cast_error_suggestion(c, x, type);
|
||||
|
||||
end_error_block();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3422,7 +3498,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
||||
|
||||
|
||||
if (token_is_comparison(op.kind)) {
|
||||
check_comparison(c, x, y, op.kind);
|
||||
check_comparison(c, node, x, y, op.kind);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4539,7 +4615,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
entity = scope_lookup_current(import_scope, entity_name);
|
||||
bool allow_builtin = false;
|
||||
if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) {
|
||||
error(op_expr, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name));
|
||||
error(node, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name));
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
|
||||
@@ -4559,7 +4635,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
|
||||
if (!is_entity_exported(entity, allow_builtin)) {
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(op_expr, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name));
|
||||
error(node, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name));
|
||||
gb_string_free(sel_str);
|
||||
// NOTE(bill): make the state valid still, even if it's "invalid"
|
||||
// operand->mode = Addressing_Invalid;
|
||||
@@ -4730,20 +4806,29 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string_shorthand(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
|
||||
|
||||
if (operand->type != nullptr && selector->kind == Ast_Ident) {
|
||||
String const &name = selector->Ident.token.string;
|
||||
Type *bt = base_type(operand->type);
|
||||
if (operand->type->kind == Type_Named &&
|
||||
operand->type->Named.type_name &&
|
||||
operand->type->Named.type_name->kind == Entity_TypeName &&
|
||||
operand->type->Named.type_name->TypeName.objc_metadata) {
|
||||
check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type);
|
||||
} else if (bt->kind == Type_Struct) {
|
||||
check_did_you_mean_type(name, bt->Struct.fields);
|
||||
} else if (bt->kind == Type_Enum) {
|
||||
check_did_you_mean_type(name, bt->Enum.fields);
|
||||
if (operand->mode == Addressing_Type) {
|
||||
if (is_type_polymorphic(operand->type, true)) {
|
||||
error(op_expr, "Type '%s' has no field nor polymorphic parameter '%s'", op_str, sel_str);
|
||||
} else {
|
||||
error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str);
|
||||
}
|
||||
} else {
|
||||
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
|
||||
|
||||
if (operand->type != nullptr && selector->kind == Ast_Ident) {
|
||||
String const &name = selector->Ident.token.string;
|
||||
Type *bt = base_type(operand->type);
|
||||
if (operand->type->kind == Type_Named &&
|
||||
operand->type->Named.type_name &&
|
||||
operand->type->Named.type_name->kind == Entity_TypeName &&
|
||||
operand->type->Named.type_name->TypeName.objc_metadata) {
|
||||
check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type);
|
||||
} else if (bt->kind == Type_Struct) {
|
||||
check_did_you_mean_type(name, bt->Struct.fields);
|
||||
} else if (bt->kind == Type_Enum) {
|
||||
check_did_you_mean_type(name, bt->Enum.fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5418,7 +5503,18 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
data->score = score;
|
||||
data->result_type = final_proc_type->Proc.results;
|
||||
data->gen_entity = gen_entity;
|
||||
add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {});
|
||||
|
||||
|
||||
Ast *proc_lit = nullptr;
|
||||
if (ce->proc->tav.value.kind == ExactValue_Procedure) {
|
||||
Ast *vp = unparen_expr(ce->proc->tav.value.value_procedure);
|
||||
if (vp && vp->kind == Ast_ProcLit) {
|
||||
proc_lit = vp;
|
||||
}
|
||||
}
|
||||
if (proc_lit == nullptr) {
|
||||
add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {});
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
@@ -7033,7 +7129,7 @@ gb_internal bool ternary_compare_types(Type *x, Type *y) {
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) {
|
||||
gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) {
|
||||
if (!is_ast_range(node)) {
|
||||
return false;
|
||||
}
|
||||
@@ -7082,9 +7178,17 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *
|
||||
}
|
||||
|
||||
Type *type = x->type;
|
||||
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
|
||||
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
||||
return false;
|
||||
|
||||
if (is_for_loop) {
|
||||
if (!is_type_integer(type) && !is_type_float(type) && !is_type_enum(type)) {
|
||||
error(ie->op, "Only numerical types are allowed within interval expressions");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
|
||||
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (x->mode == Addressing_Constant &&
|
||||
@@ -7790,6 +7894,124 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
|
||||
gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<Ast *> const &elems, Operand *o, Type *type, bool &is_constant) {
|
||||
Type *bt = base_type(type);
|
||||
|
||||
StringSet fields_visited = {};
|
||||
defer (string_set_destroy(&fields_visited));
|
||||
|
||||
StringMap<String> fields_visited_through_raw_union = {};
|
||||
defer (string_map_destroy(&fields_visited_through_raw_union));
|
||||
|
||||
for (Ast *elem : elems) {
|
||||
if (elem->kind != Ast_FieldValue) {
|
||||
error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
|
||||
continue;
|
||||
}
|
||||
ast_node(fv, FieldValue, elem);
|
||||
if (fv->field->kind != Ast_Ident) {
|
||||
gbString expr_str = expr_to_string(fv->field);
|
||||
error(elem, "Invalid field name '%s' in structure literal", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
continue;
|
||||
}
|
||||
String name = fv->field->Ident.token.string;
|
||||
|
||||
Selection sel = lookup_field(type, name, o->mode == Addressing_Type);
|
||||
bool is_unknown = sel.entity == nullptr;
|
||||
if (is_unknown) {
|
||||
error(fv->field, "Unknown field '%.*s' in structure literal", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity *field = bt->Struct.fields[sel.index[0]];
|
||||
add_entity_use(c, fv->field, field);
|
||||
if (string_set_update(&fields_visited, name)) {
|
||||
if (sel.index.count > 1) {
|
||||
if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) {
|
||||
error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found));
|
||||
} else {
|
||||
error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string));
|
||||
}
|
||||
} else {
|
||||
error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string));
|
||||
}
|
||||
continue;
|
||||
} else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) {
|
||||
error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found));
|
||||
continue;
|
||||
}
|
||||
if (sel.indirect) {
|
||||
error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sel.index.count > 1) {
|
||||
if (is_constant) {
|
||||
Type *ft = type;
|
||||
for (i32 index : sel.index) {
|
||||
Type *bt = base_type(ft);
|
||||
switch (bt->kind) {
|
||||
case Type_Struct:
|
||||
if (bt->Struct.is_raw_union) {
|
||||
is_constant = false;
|
||||
break;
|
||||
}
|
||||
ft = bt->Struct.fields[index]->type;
|
||||
break;
|
||||
case Type_Array:
|
||||
ft = bt->Array.elem;
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("invalid type: %s", type_to_string(ft));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_constant &&
|
||||
(is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) {
|
||||
is_constant = false;
|
||||
}
|
||||
}
|
||||
|
||||
Type *nested_ft = bt;
|
||||
for (i32 index : sel.index) {
|
||||
Type *bt = base_type(nested_ft);
|
||||
switch (bt->kind) {
|
||||
case Type_Struct:
|
||||
if (bt->Struct.is_raw_union) {
|
||||
for (Entity *re : bt->Struct.fields) {
|
||||
string_map_set(&fields_visited_through_raw_union, re->token.string, sel.entity->token.string);
|
||||
}
|
||||
}
|
||||
nested_ft = bt->Struct.fields[index]->type;
|
||||
break;
|
||||
case Type_Array:
|
||||
nested_ft = bt->Array.elem;
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("invalid type %s", type_to_string(nested_ft));
|
||||
break;
|
||||
}
|
||||
}
|
||||
field = sel.entity;
|
||||
}
|
||||
|
||||
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, fv->value, field->type);
|
||||
|
||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
||||
ExprKind kind = Expr_Expr;
|
||||
ast_node(cl, CompoundLit, node);
|
||||
@@ -7877,45 +8099,13 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count);
|
||||
gb_string_free(type_str);
|
||||
} else {
|
||||
Ast *elem = cl->elems[0];
|
||||
ast_node(fv, FieldValue, elem);
|
||||
if (fv->field->kind != Ast_Ident) {
|
||||
gbString expr_str = expr_to_string(fv->field);
|
||||
error(elem, "Invalid field name '%s' in structure literal", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
break;
|
||||
}
|
||||
|
||||
String name = fv->field->Ident.token.string;
|
||||
|
||||
Selection sel = lookup_field(type, name, o->mode == Addressing_Type);
|
||||
bool is_unknown = sel.entity == nullptr;
|
||||
if (is_unknown) {
|
||||
error(elem, "Unknown field '%.*s' in structure literal", LIT(name));
|
||||
break;
|
||||
}
|
||||
|
||||
if (sel.index.count > 1) {
|
||||
error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name));
|
||||
break;
|
||||
}
|
||||
|
||||
Entity *field = t->Struct.fields[sel.index[0]];
|
||||
add_entity_use(c, fv->field, field);
|
||||
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, fv->value, field->type);
|
||||
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
isize field_count = t->Struct.fields.count;
|
||||
isize min_field_count = t->Struct.fields.count;
|
||||
for (isize i = min_field_count-1; i >= 0; i--) {
|
||||
@@ -7929,58 +8119,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
}
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count);
|
||||
|
||||
for (Ast *elem : cl->elems) {
|
||||
if (elem->kind != Ast_FieldValue) {
|
||||
error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
|
||||
continue;
|
||||
}
|
||||
ast_node(fv, FieldValue, elem);
|
||||
if (fv->field->kind != Ast_Ident) {
|
||||
gbString expr_str = expr_to_string(fv->field);
|
||||
error(elem, "Invalid field name '%s' in structure literal", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
continue;
|
||||
}
|
||||
String name = fv->field->Ident.token.string;
|
||||
|
||||
Selection sel = lookup_field(type, name, o->mode == Addressing_Type);
|
||||
bool is_unknown = sel.entity == nullptr;
|
||||
if (is_unknown) {
|
||||
error(elem, "Unknown field '%.*s' in structure literal", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sel.index.count > 1) {
|
||||
error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity *field = t->Struct.fields[sel.index[0]];
|
||||
add_entity_use(c, fv->field, field);
|
||||
|
||||
if (fields_visited[sel.index[0]]) {
|
||||
error(elem, "Duplicate field '%.*s' in structure literal", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
fields_visited[sel.index[0]] = true;
|
||||
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, fv->value, field->type);
|
||||
|
||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
}
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
} else {
|
||||
bool seen_field_value = false;
|
||||
|
||||
@@ -8097,7 +8236,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
bool ok = check_range(c, fv->field, &x, &y, nullptr);
|
||||
bool ok = check_range(c, fv->field, false, &x, &y, nullptr);
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
@@ -8313,7 +8452,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
bool ok = check_range(c, fv->field, &x, &y, nullptr, index_type);
|
||||
bool ok = check_range(c, fv->field, false, &x, &y, nullptr, index_type);
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user