mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
Make typeid semantics consistent across variables and constants
This commit is contained in:
+37
-17
@@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
gbString t = type_to_string(operand->type);
|
||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
gb_string_free(t);
|
||||
e->type = operand->type;
|
||||
return nullptr;
|
||||
if (e->type != nullptr && is_type_typeid(e->type)) {
|
||||
add_type_info_type(ctx, operand->type);
|
||||
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
|
||||
return e->type;
|
||||
} else {
|
||||
gbString t = type_to_string(operand->type);
|
||||
defer (gb_string_free(t));
|
||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
if (e->type == nullptr) {
|
||||
error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string));
|
||||
}
|
||||
e->type = operand->type;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
|
||||
}
|
||||
|
||||
|
||||
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
|
||||
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
@@ -248,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
|
||||
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool is_distinct = is_type_distinct(type_expr);
|
||||
Ast *te = remove_type_alias_clutter(type_expr);
|
||||
bool is_distinct = is_type_distinct(init_expr);
|
||||
Ast *te = remove_type_alias_clutter(init_expr);
|
||||
e->type = t_invalid;
|
||||
String name = e->token.string;
|
||||
Type *named = alloc_type_named(name, nullptr, e);
|
||||
@@ -266,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
|
||||
named->Named.base = base_type(bt);
|
||||
|
||||
if (is_distinct && is_type_typeid(e->type)) {
|
||||
error(type_expr, "'distinct' cannot be applied to 'typeid'");
|
||||
error(init_expr, "'distinct' cannot be applied to 'typeid'");
|
||||
is_distinct = false;
|
||||
}
|
||||
if (!is_distinct) {
|
||||
@@ -275,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
|
||||
e->TypeName.is_type_alias = true;
|
||||
}
|
||||
|
||||
|
||||
if (decl->type_expr != nullptr) {
|
||||
Type *t = check_type(ctx, decl->type_expr);
|
||||
if (t != nullptr && !is_type_typeid(t)) {
|
||||
Operand operand = {};
|
||||
operand.mode = Addressing_Type;
|
||||
operand.type = e->type;
|
||||
operand.expr = init_expr;
|
||||
check_assignment(ctx, &operand, t, str_lit("constant declaration"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// using decl
|
||||
if (decl->is_using) {
|
||||
// NOTE(bill): Must be an enum declaration
|
||||
@@ -363,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
||||
|
||||
switch (operand.mode) {
|
||||
case Addressing_Type: {
|
||||
if (e->type != nullptr && !is_type_typeid(e->type)) {
|
||||
check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
|
||||
}
|
||||
|
||||
e->kind = Entity_TypeName;
|
||||
e->type = nullptr;
|
||||
|
||||
DeclInfo *d = ctx->decl;
|
||||
if (d->type_expr != nullptr) {
|
||||
error(e->token, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = d->init_expr;
|
||||
check_type_decl(ctx, e, d->type_expr, named_type);
|
||||
check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1070,7 +1090,7 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
|
||||
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
|
||||
break;
|
||||
case Entity_TypeName: {
|
||||
check_type_decl(&c, e, d->type_expr, named_type);
|
||||
check_type_decl(&c, e, d->init_expr, named_type);
|
||||
break;
|
||||
}
|
||||
case Entity_Procedure:
|
||||
|
||||
+47
-14
@@ -442,6 +442,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
if (is_type_typeid(type)) {
|
||||
add_type_info_type(c, operand->type);
|
||||
return 4;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -755,7 +759,12 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_is_assignable_to(c, operand, type)) {
|
||||
if (check_is_assignable_to(c, operand, type)) {
|
||||
if (operand->mode == Addressing_Type && is_type_typeid(type)) {
|
||||
add_type_info_type(c, operand->type);
|
||||
add_type_and_value(c->info, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type));
|
||||
}
|
||||
} else {
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
gbString op_type_str = type_to_string(operand->type);
|
||||
gbString type_str = type_to_string(type);
|
||||
@@ -1734,6 +1743,23 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x->mode == Addressing_Type && is_type_typeid(y->type)) {
|
||||
add_type_info_type(c, x->type);
|
||||
add_type_and_value(c->info, x->expr, Addressing_Value, y->type, exact_value_typeid(x->type));
|
||||
|
||||
x->mode = Addressing_Value;
|
||||
x->type = t_untyped_bool;
|
||||
return;
|
||||
} else if (is_type_typeid(x->type) && y->mode == Addressing_Type) {
|
||||
add_type_info_type(c, y->type);
|
||||
add_type_and_value(c->info, y->expr, Addressing_Value, x->type, exact_value_typeid(y->type));
|
||||
|
||||
x->mode = Addressing_Value;
|
||||
x->type = t_untyped_bool;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gbString err_str = nullptr;
|
||||
|
||||
defer (if (err_str != nullptr) {
|
||||
@@ -2324,8 +2350,16 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint
|
||||
// If only one is a type, this is an error
|
||||
if (xt ^ yt) {
|
||||
GB_ASSERT(xt != yt);
|
||||
if (xt) error_operand_not_expression(x);
|
||||
if (yt) error_operand_not_expression(y);
|
||||
if (xt) {
|
||||
if (!is_type_typeid(y->type)) {
|
||||
error_operand_not_expression(x);
|
||||
}
|
||||
}
|
||||
if (yt) {
|
||||
if (!is_type_typeid(x->type)) {
|
||||
error_operand_not_expression(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -5254,6 +5288,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
}
|
||||
}
|
||||
score += s;
|
||||
|
||||
if (o.mode == Addressing_Type && is_type_typeid(e->type)) {
|
||||
add_type_info_type(c, o.type);
|
||||
add_type_and_value(c->info, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type));
|
||||
}
|
||||
}
|
||||
|
||||
if (variadic) {
|
||||
@@ -5496,6 +5535,11 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
}
|
||||
score += s;
|
||||
}
|
||||
|
||||
if (o->mode == Addressing_Type && is_type_typeid(e->type)) {
|
||||
add_type_info_type(c, o->type);
|
||||
add_type_and_value(c->info, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type));
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
@@ -6432,17 +6476,6 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): Should this be here or on the `add_entity_use`?
|
||||
// if (ce->proc != nullptr) {
|
||||
// Entity *e = entity_of_node(&c->info, ce->proc);
|
||||
// if (e != nullptr && e->kind == Entity_Procedure) {
|
||||
// String msg = e->Procedure.deprecated_message;
|
||||
// if (msg.len > 0) {
|
||||
// warning(call, "%.*s is deprecated: %.*s", LIT(e->token.string), LIT(msg));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
|
||||
Type *result_type = data.result_type;
|
||||
gb_zero_item(operand);
|
||||
|
||||
+6
-10
@@ -2613,14 +2613,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
Entity *e = nullptr;
|
||||
|
||||
d->attributes = vd->attributes;
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
|
||||
if (is_ast_type(init)) {
|
||||
e = alloc_entity_type_name(d->scope, token, nullptr);
|
||||
if (vd->type != nullptr) {
|
||||
error(name, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = init;
|
||||
d->init_expr = init;
|
||||
// if (vd->type != nullptr) {
|
||||
// error(name, "A type declaration cannot have an type parameter");
|
||||
// }
|
||||
} else if (init->kind == Ast_ProcLit) {
|
||||
if (c->scope->flags&ScopeFlag_Type) {
|
||||
error(name, "Procedure declarations are not allowed within a struct");
|
||||
@@ -2647,19 +2647,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
pl->type->ProcType.calling_convention = cc;
|
||||
}
|
||||
d->proc_lit = init;
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
} else if (init->kind == Ast_ProcGroup) {
|
||||
ast_node(pg, ProcGroup, init);
|
||||
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
||||
if (fl != nullptr) {
|
||||
error(name, "Procedure groups are not allowed within a foreign block");
|
||||
}
|
||||
d->init_expr = init;
|
||||
d->type_expr = vd->type;
|
||||
} else {
|
||||
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
}
|
||||
e->identifier = name;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ enum ExactValueKind {
|
||||
ExactValue_Pointer,
|
||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
||||
ExactValue_Typeid,
|
||||
|
||||
ExactValue_Count,
|
||||
};
|
||||
@@ -54,6 +55,7 @@ struct ExactValue {
|
||||
Quaternion256 value_quaternion;
|
||||
Ast * value_compound;
|
||||
Ast * value_procedure;
|
||||
Type * value_typeid;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -82,6 +84,8 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
return hash_pointer(v.value_compound);
|
||||
case ExactValue_Procedure:
|
||||
return hash_pointer(v.value_procedure);
|
||||
case ExactValue_Typeid:
|
||||
return hash_pointer(v.value_typeid);
|
||||
}
|
||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
||||
|
||||
@@ -154,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) {
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_typeid(Type *type) {
|
||||
ExactValue result = {ExactValue_Typeid};
|
||||
result.value_typeid = type;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_integer_from_string(String const &string) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
big_int_from_string(&result.value_integer, string);
|
||||
@@ -889,6 +900,13 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ExactValue_Typeid:
|
||||
switch (op) {
|
||||
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
|
||||
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GB_PANIC("Invalid comparison");
|
||||
|
||||
@@ -6592,6 +6592,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
||||
return ir_emit_conv(proc, x, tv.type);
|
||||
}
|
||||
|
||||
if (tv.value.kind == ExactValue_Typeid) {
|
||||
irValue *v = ir_typeid(proc->module, tv.value.value_typeid);
|
||||
return ir_emit_conv(proc, v, tv.type);
|
||||
}
|
||||
|
||||
return ir_add_module_constant(proc->module, tv.type, tv.value);
|
||||
}
|
||||
|
||||
|
||||
@@ -1923,10 +1923,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
case Token_typeid: {
|
||||
Token token = expect_token(f, Token_typeid);
|
||||
// Ast *specialization = nullptr;
|
||||
// if (allow_token(f, Token_Quo)) {
|
||||
// specialization = parse_type(f);
|
||||
// }
|
||||
return ast_typeid_type(f, token, nullptr);
|
||||
} break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user