mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 17:32:22 -07:00
#const value procedure parameters; $N for polymorphic array lengths
This commit is contained in:
+93
-32
@@ -686,7 +686,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
specialization = nullptr;
|
||||
}
|
||||
}
|
||||
type = make_type_generic(c->allocator, 0, str_lit(""), specialization);
|
||||
type = make_type_generic(c->allocator, c->context.scope, 0, str_lit(""), specialization);
|
||||
} else {
|
||||
type = check_type(c, type_expr);
|
||||
if (is_type_polymorphic(type)) {
|
||||
@@ -1270,6 +1270,9 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
bool detemine_type_from_operand = false;
|
||||
Type *specialization = nullptr;
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
bool is_constant_value = (p->flags&FieldFlag_const) != 0;
|
||||
|
||||
|
||||
if (type_expr == nullptr) {
|
||||
if (default_value->kind == AstNode_BasicDirective &&
|
||||
@@ -1338,7 +1341,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
detemine_type_from_operand = true;
|
||||
type = t_invalid;
|
||||
} else {
|
||||
type = make_type_generic(c->allocator, 0, str_lit(""), specialization);
|
||||
type = make_type_generic(c->allocator, c->context.scope, 0, str_lit(""), specialization);
|
||||
}
|
||||
} else {
|
||||
bool prev = c->context.allow_polymorphic_types;
|
||||
@@ -1357,6 +1360,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
if (default_value != nullptr) {
|
||||
if (type_expr->kind == AstNode_TypeType) {
|
||||
error(default_value, "A type parameter may not have a default value");
|
||||
} else if (is_constant_value) {
|
||||
error(default_value, "A constant parameter may not have a default value");
|
||||
} else {
|
||||
Operand o = {};
|
||||
if (default_value->kind == AstNode_BasicDirective &&
|
||||
@@ -1431,6 +1436,16 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
}
|
||||
|
||||
if (is_constant_value) {
|
||||
if (is_type_param) {
|
||||
error(p->type, "`$` is not needed for a `type` parameter");
|
||||
}
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
error(p->type, "`#no_alias` can only be applied to variable fields of pointer type");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for_array(j, p->names) {
|
||||
AstNode *name = p->names[j];
|
||||
@@ -1475,16 +1490,16 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
param = make_entity_type_name(c->allocator, scope, name->Ident.token, type);
|
||||
param->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
if (operands != nullptr && is_type_polymorphic_type &&
|
||||
operands->count > variables.count) {
|
||||
Operand op = (*operands)[variables.count];
|
||||
type = determine_type_from_polymorphic(c, type, op);
|
||||
if (type == t_invalid) {
|
||||
success = false;
|
||||
} else if (!c->context.no_polymorphic_errors) {
|
||||
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
|
||||
is_type_polymorphic_type = false;
|
||||
// is_type_polymorphic_type = is_type_polymorphic(base_type(type));
|
||||
if (operands != nullptr && variables.count < operands->count) {
|
||||
if (is_type_polymorphic_type) {
|
||||
Operand op = (*operands)[variables.count];
|
||||
type = determine_type_from_polymorphic(c, type, op);
|
||||
if (type == t_invalid) {
|
||||
success = false;
|
||||
} else if (!c->context.no_polymorphic_errors) {
|
||||
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
|
||||
is_type_polymorphic_type = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1495,11 +1510,33 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
}
|
||||
|
||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type,
|
||||
(p->flags&FieldFlag_using) != 0, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
param->Variable.default_is_location = default_is_location;
|
||||
if (is_constant_value) {
|
||||
if (!is_type_constant_type(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(params[i], "Invalid constant type, %s", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
|
||||
bool poly_const = true;
|
||||
if (operands != nullptr) {
|
||||
poly_const = false;
|
||||
if (variables.count < operands->count) {
|
||||
Operand op = (*operands)[variables.count];
|
||||
if (op.mode != Addressing_Constant) {
|
||||
error(op.expr, "Expected a constant parameter value");
|
||||
} else {
|
||||
value = op.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
param = make_entity_const_param(c->allocator, scope, name->Ident.token, type, value, poly_const);
|
||||
} else {
|
||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type, is_using, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
param->Variable.default_is_location = default_is_location;
|
||||
}
|
||||
|
||||
}
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
@@ -1952,27 +1989,36 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
||||
}
|
||||
|
||||
|
||||
i64 check_array_count(Checker *c, AstNode *e) {
|
||||
i64 check_array_count(Checker *c, Operand *o, AstNode *e) {
|
||||
if (e == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
Operand o = {};
|
||||
if (e->kind == AstNode_UnaryExpr &&
|
||||
e->UnaryExpr.op.kind == Token_Ellipsis) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
check_expr(c, &o, e);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
check_expr_or_type(c, o, e);
|
||||
if (o->mode == Addressing_Type && o->type->kind == Type_Generic) {
|
||||
if (c->context.allow_polymorphic_types) {
|
||||
if (o->type->Generic.specialized) {
|
||||
o->type->Generic.specialized = nullptr;
|
||||
error(o->expr, "Polymorphic array length cannot have a specialization");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (o->mode != Addressing_Constant) {
|
||||
if (o->mode != Addressing_Invalid) {
|
||||
o->mode = Addressing_Invalid;
|
||||
error(e, "Array count must be a constant");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Type *type = base_type(o.type);
|
||||
Type *type = base_type(o->type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o.value.kind == ExactValue_Integer) {
|
||||
i64 count = i128_to_i64(o.value.value_integer);
|
||||
if (o->value.kind == ExactValue_Integer) {
|
||||
i64 count = i128_to_i64(o->value.value_integer);
|
||||
if (count >= 0) {
|
||||
return count;
|
||||
}
|
||||
@@ -2162,7 +2208,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
specific = nullptr;
|
||||
}
|
||||
}
|
||||
Type *t = make_type_generic(c->allocator, 0, token.string, specific);
|
||||
Type *t = make_type_generic(c->allocator, c->context.scope, 0, token.string, specific);
|
||||
if (c->context.allow_polymorphic_types) {
|
||||
Scope *ps = c->context.polymorphic_scope;
|
||||
Scope *s = c->context.scope;
|
||||
@@ -2176,7 +2222,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
add_entity(c, ps, ident, e);
|
||||
add_entity(c, s, ident, e);
|
||||
} else {
|
||||
error(ident, "Invalid use of a polymorphic type `$%.*s`", LIT(token.string));
|
||||
error(ident, "Invalid use of a polymorphic parameter `$%.*s`", LIT(token.string));
|
||||
*type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
@@ -2233,13 +2279,18 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
|
||||
case_ast_node(at, ArrayType, e);
|
||||
if (at->count != nullptr) {
|
||||
Type *elem = check_type(c, at->elem, nullptr);
|
||||
i64 count = check_array_count(c, at->count);
|
||||
Operand o = {};
|
||||
i64 count = check_array_count(c, &o, at->count);
|
||||
Type *generic_type = nullptr;
|
||||
if (o.mode == Addressing_Type && o.type->kind == Type_Generic) {
|
||||
generic_type = o.type;
|
||||
}
|
||||
if (count < 0) {
|
||||
error(at->count, "... can only be used in conjuction with compound literals");
|
||||
count = 0;
|
||||
}
|
||||
*type = make_type_array(c->allocator, elem, count);
|
||||
Type *elem = check_type(c, at->elem, nullptr);
|
||||
*type = make_type_array(c->allocator, elem, count, generic_type);
|
||||
} else {
|
||||
Type *elem = check_type(c, at->elem);
|
||||
*type = make_type_slice(c->allocator, elem);
|
||||
@@ -2256,15 +2307,25 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
|
||||
|
||||
case_ast_node(vt, VectorType, e);
|
||||
|
||||
Operand o = {};
|
||||
i64 count = check_array_count(c, &o, vt->count);
|
||||
Type *generic_type = nullptr;
|
||||
if (o.mode == Addressing_Type && o.type->kind == Type_Generic) {
|
||||
generic_type = o.type;
|
||||
}
|
||||
if (count < 0) {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
Type *elem = check_type(c, vt->elem);
|
||||
Type *be = base_type(elem);
|
||||
i64 count = check_array_count(c, vt->count);
|
||||
if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be) && be->kind != Type_Generic)) {
|
||||
gbString err_str = type_to_string(elem);
|
||||
error(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str);
|
||||
gb_string_free(err_str);
|
||||
}
|
||||
*type = make_type_vector(c->allocator, elem, count);
|
||||
*type = make_type_vector(c->allocator, elem, count, generic_type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user