mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Fix default parameters on record types
This commit is contained in:
+53
-10
@@ -7338,6 +7338,7 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
|
|||||||
Entity *e = params->variables[i];
|
Entity *e = params->variables[i];
|
||||||
if (e->kind == Entity_Constant) {
|
if (e->kind == Entity_Constant) {
|
||||||
check_expr_with_type_hint(c, &operands[i], fv->value, e->type);
|
check_expr_with_type_hint(c, &operands[i], fv->value, e->type);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7371,9 +7372,22 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
|
|||||||
|
|
||||||
TypeTuple *tuple = get_record_polymorphic_params(original_type);
|
TypeTuple *tuple = get_record_polymorphic_params(original_type);
|
||||||
isize param_count = tuple->variables.count;
|
isize param_count = tuple->variables.count;
|
||||||
|
isize minimum_param_count = param_count;
|
||||||
|
for (minimum_param_count = tuple->variables.count-1; minimum_param_count >= 0; minimum_param_count--) {
|
||||||
|
Entity *e = tuple->variables[minimum_param_count];
|
||||||
|
if (e->kind != Entity_Constant) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (e->Constant.param_value.kind == ParameterValue_Invalid) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Array<Operand> ordered_operands = operands;
|
Array<Operand> ordered_operands = operands;
|
||||||
if (named_fields) {
|
if (!named_fields) {
|
||||||
|
ordered_operands = array_make<Operand>(c->allocator, param_count);
|
||||||
|
array_copy(&ordered_operands, operands, 0);
|
||||||
|
} else {
|
||||||
bool *visited = gb_alloc_array(c->allocator, bool, param_count);
|
bool *visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||||
|
|
||||||
// LEAK(bill)
|
// LEAK(bill)
|
||||||
@@ -7440,26 +7454,55 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param_count < ordered_operands.count) {
|
if (minimum_param_count != param_count) {
|
||||||
error(call, "Too many polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
|
if (param_count < ordered_operands.count) {
|
||||||
err = CallArgumentError_TooManyArguments;
|
error(call, "Too many polymorphic type arguments, expected a maximum of %td, got %td", param_count, ordered_operands.count);
|
||||||
} else if (param_count > ordered_operands.count) {
|
err = CallArgumentError_TooManyArguments;
|
||||||
error(call, "Too few polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
|
} else if (minimum_param_count > ordered_operands.count) {
|
||||||
err = CallArgumentError_TooFewArguments;
|
error(call, "Too few polymorphic type arguments, expected a minimum of %td, got %td", minimum_param_count, ordered_operands.count);
|
||||||
|
err = CallArgumentError_TooFewArguments;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (param_count < ordered_operands.count) {
|
||||||
|
error(call, "Too many polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
|
||||||
|
err = CallArgumentError_TooManyArguments;
|
||||||
|
} else if (param_count > ordered_operands.count) {
|
||||||
|
error(call, "Too few polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
|
||||||
|
err = CallArgumentError_TooFewArguments;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (minimum_param_count != param_count) {
|
||||||
|
isize missing_count = 0;
|
||||||
|
// NOTE(bill): Replace missing operands with the default values (if possible)
|
||||||
|
for_array(i, ordered_operands) {
|
||||||
|
Operand *o = &ordered_operands[i];
|
||||||
|
if (o->expr == nullptr) {
|
||||||
|
Entity *e = tuple->variables[i];
|
||||||
|
if (e->kind == Entity_Constant) {
|
||||||
|
missing_count += 1;
|
||||||
|
o->mode = Addressing_Constant;
|
||||||
|
o->type = default_type(e->type);
|
||||||
|
o->expr = unparen_expr(e->Constant.param_value.original_ast_expr);
|
||||||
|
if (e->Constant.param_value.kind == ParameterValue_Constant) {
|
||||||
|
o->value = e->Constant.param_value.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i64 score = 0;
|
i64 score = 0;
|
||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
|
Entity *e = tuple->variables[i];
|
||||||
Operand *o = &ordered_operands[i];
|
Operand *o = &ordered_operands[i];
|
||||||
if (o->mode == Addressing_Invalid) {
|
if (o->mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Entity *e = tuple->variables[i];
|
|
||||||
|
|
||||||
if (e->kind == Entity_TypeName) {
|
if (e->kind == Entity_TypeName) {
|
||||||
if (o->mode != Addressing_Type) {
|
if (o->mode != Addressing_Type) {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
@@ -7800,7 +7843,7 @@ void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t) {
|
|||||||
err_str = "used as a value";
|
err_str = "used as a value";
|
||||||
break;
|
break;
|
||||||
case Addressing_Type:
|
case Addressing_Type:
|
||||||
err_str = "is not an expression";
|
err_str = "is not an expression but a";
|
||||||
break;
|
break;
|
||||||
case Addressing_Builtin:
|
case Addressing_Builtin:
|
||||||
err_str = "must be called";
|
err_str = "must be called";
|
||||||
|
|||||||
+88
-35
@@ -1,3 +1,4 @@
|
|||||||
|
ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
|
||||||
|
|
||||||
void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
|
void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
@@ -408,32 +409,50 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
}
|
}
|
||||||
ast_node(p, Field, param);
|
ast_node(p, Field, param);
|
||||||
Ast *type_expr = p->type;
|
Ast *type_expr = p->type;
|
||||||
|
Ast *default_value = unparen_expr(p->default_value);
|
||||||
Type *type = nullptr;
|
Type *type = nullptr;
|
||||||
bool is_type_param = false;
|
bool is_type_param = false;
|
||||||
bool is_type_polymorphic_type = false;
|
bool is_type_polymorphic_type = false;
|
||||||
if (type_expr == nullptr) {
|
if (type_expr == nullptr && default_value == nullptr) {
|
||||||
error(param, "Expected a type for this parameter");
|
error(param, "Expected a type for this parameter");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (type_expr->kind == Ast_Ellipsis) {
|
|
||||||
type_expr = type_expr->Ellipsis.expr;
|
if (type_expr != nullptr) {
|
||||||
error(param, "A polymorphic parameter cannot be variadic");
|
if (type_expr->kind == Ast_Ellipsis) {
|
||||||
}
|
type_expr = type_expr->Ellipsis.expr;
|
||||||
if (type_expr->kind == Ast_TypeidType) {
|
error(param, "A polymorphic parameter cannot be variadic");
|
||||||
is_type_param = true;
|
|
||||||
Type *specialization = nullptr;
|
|
||||||
if (type_expr->TypeidType.specialization != nullptr) {
|
|
||||||
Ast *s = type_expr->TypeidType.specialization;
|
|
||||||
specialization = check_type(ctx, s);
|
|
||||||
}
|
}
|
||||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
if (type_expr->kind == Ast_TypeidType) {
|
||||||
} else {
|
is_type_param = true;
|
||||||
type = check_type(ctx, type_expr);
|
Type *specialization = nullptr;
|
||||||
if (is_type_polymorphic(type)) {
|
if (type_expr->TypeidType.specialization != nullptr) {
|
||||||
is_type_polymorphic_type = true;
|
Ast *s = type_expr->TypeidType.specialization;
|
||||||
|
specialization = check_type(ctx, s);
|
||||||
|
}
|
||||||
|
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||||
|
} else {
|
||||||
|
type = check_type(ctx, type_expr);
|
||||||
|
if (is_type_polymorphic(type)) {
|
||||||
|
is_type_polymorphic_type = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParameterValue param_value = {};
|
||||||
|
if (default_value != nullptr) {
|
||||||
|
Type *out_type = nullptr;
|
||||||
|
param_value = handle_parameter_value(ctx, type, &out_type, default_value, false);
|
||||||
|
if (type == nullptr && out_type != nullptr) {
|
||||||
|
type = out_type;
|
||||||
|
}
|
||||||
|
if (param_value.kind != ParameterValue_Constant && param_value.kind != ParameterValue_Nil) {
|
||||||
|
error(default_value, "Invalid parameter value");
|
||||||
|
param_value = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type == nullptr) {
|
if (type == nullptr) {
|
||||||
error(params[i], "Invalid parameter type");
|
error(params[i], "Invalid parameter type");
|
||||||
type = t_invalid;
|
type = t_invalid;
|
||||||
@@ -471,7 +490,14 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
Token token = name->Ident.token;
|
Token token = name->Ident.token;
|
||||||
|
|
||||||
if (poly_operands != nullptr) {
|
if (poly_operands != nullptr) {
|
||||||
Operand operand = (*poly_operands)[entities.count];
|
Operand operand = {};
|
||||||
|
operand.type = t_invalid;
|
||||||
|
if (entities.count < poly_operands->count) {
|
||||||
|
operand = (*poly_operands)[entities.count];
|
||||||
|
} else if (param_value.kind != ParameterValue_Invalid) {
|
||||||
|
operand.mode = Addressing_Constant;
|
||||||
|
operand.value = param_value.value;
|
||||||
|
}
|
||||||
if (is_type_param) {
|
if (is_type_param) {
|
||||||
if (is_type_polymorphic(base_type(operand.type))) {
|
if (is_type_polymorphic(base_type(operand.type))) {
|
||||||
is_polymorphic = true;
|
is_polymorphic = true;
|
||||||
@@ -486,6 +512,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
}
|
}
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||||
|
e->Constant.param_value = param_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -493,7 +520,8 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
e = alloc_entity_type_name(scope, token, type);
|
e = alloc_entity_type_name(scope, token, type);
|
||||||
e->TypeName.is_type_alias = true;
|
e->TypeName.is_type_alias = true;
|
||||||
} else {
|
} else {
|
||||||
e = alloc_entity_constant(scope, token, type, empty_exact_value);
|
e = alloc_entity_constant(scope, token, type, param_value.value);
|
||||||
|
e->Constant.param_value = param_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,29 +627,45 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
|||||||
}
|
}
|
||||||
ast_node(p, Field, param);
|
ast_node(p, Field, param);
|
||||||
Ast *type_expr = p->type;
|
Ast *type_expr = p->type;
|
||||||
|
Ast *default_value = unparen_expr(p->default_value);
|
||||||
Type *type = nullptr;
|
Type *type = nullptr;
|
||||||
bool is_type_param = false;
|
bool is_type_param = false;
|
||||||
bool is_type_polymorphic_type = false;
|
bool is_type_polymorphic_type = false;
|
||||||
if (type_expr == nullptr) {
|
if (type_expr == nullptr && default_value == nullptr) {
|
||||||
error(param, "Expected a type for this parameter");
|
error(param, "Expected a type for this parameter");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (type_expr->kind == Ast_Ellipsis) {
|
if (type_expr != nullptr) {
|
||||||
type_expr = type_expr->Ellipsis.expr;
|
if (type_expr->kind == Ast_Ellipsis) {
|
||||||
error(param, "A polymorphic parameter cannot be variadic");
|
type_expr = type_expr->Ellipsis.expr;
|
||||||
}
|
error(param, "A polymorphic parameter cannot be variadic");
|
||||||
if (type_expr->kind == Ast_TypeidType) {
|
|
||||||
is_type_param = true;
|
|
||||||
Type *specialization = nullptr;
|
|
||||||
if (type_expr->TypeidType.specialization != nullptr) {
|
|
||||||
Ast *s = type_expr->TypeidType.specialization;
|
|
||||||
specialization = check_type(ctx, s);
|
|
||||||
}
|
}
|
||||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
if (type_expr->kind == Ast_TypeidType) {
|
||||||
} else {
|
is_type_param = true;
|
||||||
type = check_type(ctx, type_expr);
|
Type *specialization = nullptr;
|
||||||
if (is_type_polymorphic(type)) {
|
if (type_expr->TypeidType.specialization != nullptr) {
|
||||||
is_type_polymorphic_type = true;
|
Ast *s = type_expr->TypeidType.specialization;
|
||||||
|
specialization = check_type(ctx, s);
|
||||||
|
}
|
||||||
|
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||||
|
} else {
|
||||||
|
type = check_type(ctx, type_expr);
|
||||||
|
if (is_type_polymorphic(type)) {
|
||||||
|
is_type_polymorphic_type = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterValue param_value = {};
|
||||||
|
if (default_value != nullptr) {
|
||||||
|
Type *out_type = nullptr;
|
||||||
|
param_value = handle_parameter_value(ctx, type, &out_type, default_value, false);
|
||||||
|
if (type == nullptr && out_type != nullptr) {
|
||||||
|
type = out_type;
|
||||||
|
}
|
||||||
|
if (param_value.kind != ParameterValue_Constant && param_value.kind != ParameterValue_Nil) {
|
||||||
|
error(default_value, "Invalid parameter value");
|
||||||
|
param_value = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,7 +706,14 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
|||||||
Token token = name->Ident.token;
|
Token token = name->Ident.token;
|
||||||
|
|
||||||
if (poly_operands != nullptr) {
|
if (poly_operands != nullptr) {
|
||||||
Operand operand = (*poly_operands)[entities.count];
|
Operand operand = {};
|
||||||
|
operand.type = t_invalid;
|
||||||
|
if (entities.count < poly_operands->count) {
|
||||||
|
operand = (*poly_operands)[entities.count];
|
||||||
|
} else if (param_value.kind != ParameterValue_Invalid) {
|
||||||
|
operand.mode = Addressing_Constant;
|
||||||
|
operand.value = param_value.value;
|
||||||
|
}
|
||||||
if (is_type_param) {
|
if (is_type_param) {
|
||||||
GB_ASSERT(operand.mode == Addressing_Type ||
|
GB_ASSERT(operand.mode == Addressing_Type ||
|
||||||
operand.mode == Addressing_Invalid);
|
operand.mode == Addressing_Invalid);
|
||||||
@@ -675,6 +726,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
|||||||
} else {
|
} else {
|
||||||
// GB_ASSERT(operand.mode == Addressing_Constant);
|
// GB_ASSERT(operand.mode == Addressing_Constant);
|
||||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||||
|
e->Constant.param_value = param_value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_type_param) {
|
if (is_type_param) {
|
||||||
@@ -682,6 +734,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
|||||||
e->TypeName.is_type_alias = true;
|
e->TypeName.is_type_alias = true;
|
||||||
} else {
|
} else {
|
||||||
e = alloc_entity_constant(scope, token, type, empty_exact_value);
|
e = alloc_entity_constant(scope, token, type, empty_exact_value);
|
||||||
|
e->Constant.param_value = param_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ struct Entity {
|
|||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
ExactValue value;
|
ExactValue value;
|
||||||
|
ParameterValue param_value;
|
||||||
} Constant;
|
} Constant;
|
||||||
struct {
|
struct {
|
||||||
Ast *init_expr; // only used for some variables within procedure bodies
|
Ast *init_expr; // only used for some variables within procedure bodies
|
||||||
|
|||||||
+2
-2
@@ -2122,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
if (allow_token(f, Token_OpenParen)) {
|
if (allow_token(f, Token_OpenParen)) {
|
||||||
isize param_count = 0;
|
isize param_count = 0;
|
||||||
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, false, true);
|
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, true, true);
|
||||||
if (param_count == 0) {
|
if (param_count == 0) {
|
||||||
syntax_error(polymorphic_params, "Expected at least 1 polymorphic parameter");
|
syntax_error(polymorphic_params, "Expected at least 1 polymorphic parameter");
|
||||||
polymorphic_params = nullptr;
|
polymorphic_params = nullptr;
|
||||||
@@ -2203,7 +2203,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
if (allow_token(f, Token_OpenParen)) {
|
if (allow_token(f, Token_OpenParen)) {
|
||||||
isize param_count = 0;
|
isize param_count = 0;
|
||||||
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, false, true);
|
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, true, true);
|
||||||
if (param_count == 0) {
|
if (param_count == 0) {
|
||||||
syntax_error(polymorphic_params, "Expected at least 1 polymorphic parametric");
|
syntax_error(polymorphic_params, "Expected at least 1 polymorphic parametric");
|
||||||
polymorphic_params = nullptr;
|
polymorphic_params = nullptr;
|
||||||
|
|||||||
Reference in New Issue
Block a user