diff options
Diffstat (limited to 'src/check_type.cpp')
| -rw-r--r-- | src/check_type.cpp | 125 |
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; |