aboutsummaryrefslogtreecommitdiff
path: root/src/check_type.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_type.cpp')
-rw-r--r--src/check_type.cpp125
1 files changed, 93 insertions, 32 deletions
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 2d881fbe0..befe56711 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -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;