mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00: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) {
|
if (operand->mode == Addressing_Type) {
|
||||||
gbString t = type_to_string(operand->type);
|
if (e->type != nullptr && is_type_typeid(e->type)) {
|
||||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
add_type_info_type(ctx, operand->type);
|
||||||
gb_string_free(t);
|
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
|
||||||
e->type = operand->type;
|
return e->type;
|
||||||
return nullptr;
|
} 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);
|
GB_ASSERT(e->type == nullptr);
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(e);
|
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);
|
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_distinct = is_type_distinct(init_expr);
|
||||||
bool is_distinct = is_type_distinct(type_expr);
|
Ast *te = remove_type_alias_clutter(init_expr);
|
||||||
Ast *te = remove_type_alias_clutter(type_expr);
|
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *named = alloc_type_named(name, nullptr, e);
|
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);
|
named->Named.base = base_type(bt);
|
||||||
|
|
||||||
if (is_distinct && is_type_typeid(e->type)) {
|
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;
|
is_distinct = false;
|
||||||
}
|
}
|
||||||
if (!is_distinct) {
|
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;
|
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
|
// using decl
|
||||||
if (decl->is_using) {
|
if (decl->is_using) {
|
||||||
// NOTE(bill): Must be an enum declaration
|
// 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) {
|
switch (operand.mode) {
|
||||||
case Addressing_Type: {
|
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->kind = Entity_TypeName;
|
||||||
e->type = nullptr;
|
e->type = nullptr;
|
||||||
|
|
||||||
DeclInfo *d = ctx->decl;
|
check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
|
||||||
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);
|
|
||||||
return;
|
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);
|
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
|
||||||
break;
|
break;
|
||||||
case Entity_TypeName: {
|
case Entity_TypeName: {
|
||||||
check_type_decl(&c, e, d->type_expr, named_type);
|
check_type_decl(&c, e, d->init_expr, named_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Entity_Procedure:
|
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 (operand->mode == Addressing_Type) {
|
||||||
|
if (is_type_typeid(type)) {
|
||||||
|
add_type_info_type(c, operand->type);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +759,12 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
|
|||||||
return;
|
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 expr_str = expr_to_string(operand->expr);
|
||||||
gbString op_type_str = type_to_string(operand->type);
|
gbString op_type_str = type_to_string(operand->type);
|
||||||
gbString type_str = type_to_string(type);
|
gbString type_str = type_to_string(type);
|
||||||
@@ -1734,6 +1743,23 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
|
|||||||
return;
|
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;
|
gbString err_str = nullptr;
|
||||||
|
|
||||||
defer (if (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 only one is a type, this is an error
|
||||||
if (xt ^ yt) {
|
if (xt ^ yt) {
|
||||||
GB_ASSERT(xt != yt);
|
GB_ASSERT(xt != yt);
|
||||||
if (xt) error_operand_not_expression(x);
|
if (xt) {
|
||||||
if (yt) error_operand_not_expression(y);
|
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;
|
break;
|
||||||
@@ -5254,6 +5288,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
score += s;
|
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) {
|
if (variadic) {
|
||||||
@@ -5496,6 +5535,11 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|||||||
}
|
}
|
||||||
score += s;
|
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) {
|
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);
|
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
|
||||||
Type *result_type = data.result_type;
|
Type *result_type = data.result_type;
|
||||||
gb_zero_item(operand);
|
gb_zero_item(operand);
|
||||||
|
|||||||
+6
-10
@@ -2613,14 +2613,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
Entity *e = nullptr;
|
Entity *e = nullptr;
|
||||||
|
|
||||||
d->attributes = vd->attributes;
|
d->attributes = vd->attributes;
|
||||||
|
d->type_expr = vd->type;
|
||||||
|
d->init_expr = init;
|
||||||
|
|
||||||
if (is_ast_type(init)) {
|
if (is_ast_type(init)) {
|
||||||
e = alloc_entity_type_name(d->scope, token, nullptr);
|
e = alloc_entity_type_name(d->scope, token, nullptr);
|
||||||
if (vd->type != nullptr) {
|
// if (vd->type != nullptr) {
|
||||||
error(name, "A type declaration cannot have an type parameter");
|
// error(name, "A type declaration cannot have an type parameter");
|
||||||
}
|
// }
|
||||||
d->type_expr = init;
|
|
||||||
d->init_expr = init;
|
|
||||||
} else if (init->kind == Ast_ProcLit) {
|
} else if (init->kind == Ast_ProcLit) {
|
||||||
if (c->scope->flags&ScopeFlag_Type) {
|
if (c->scope->flags&ScopeFlag_Type) {
|
||||||
error(name, "Procedure declarations are not allowed within a struct");
|
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;
|
pl->type->ProcType.calling_convention = cc;
|
||||||
}
|
}
|
||||||
d->proc_lit = init;
|
d->proc_lit = init;
|
||||||
d->type_expr = vd->type;
|
d->init_expr = init;
|
||||||
} else if (init->kind == Ast_ProcGroup) {
|
} else if (init->kind == Ast_ProcGroup) {
|
||||||
ast_node(pg, ProcGroup, init);
|
ast_node(pg, ProcGroup, init);
|
||||||
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
||||||
if (fl != nullptr) {
|
if (fl != nullptr) {
|
||||||
error(name, "Procedure groups are not allowed within a foreign block");
|
error(name, "Procedure groups are not allowed within a foreign block");
|
||||||
}
|
}
|
||||||
d->init_expr = init;
|
|
||||||
d->type_expr = vd->type;
|
|
||||||
} else {
|
} else {
|
||||||
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
||||||
d->type_expr = vd->type;
|
|
||||||
d->init_expr = init;
|
|
||||||
}
|
}
|
||||||
e->identifier = name;
|
e->identifier = name;
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ enum ExactValueKind {
|
|||||||
ExactValue_Pointer,
|
ExactValue_Pointer,
|
||||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||||
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
||||||
|
ExactValue_Typeid,
|
||||||
|
|
||||||
ExactValue_Count,
|
ExactValue_Count,
|
||||||
};
|
};
|
||||||
@@ -54,6 +55,7 @@ struct ExactValue {
|
|||||||
Quaternion256 value_quaternion;
|
Quaternion256 value_quaternion;
|
||||||
Ast * value_compound;
|
Ast * value_compound;
|
||||||
Ast * value_procedure;
|
Ast * value_procedure;
|
||||||
|
Type * value_typeid;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,6 +84,8 @@ HashKey hash_exact_value(ExactValue v) {
|
|||||||
return hash_pointer(v.value_compound);
|
return hash_pointer(v.value_compound);
|
||||||
case ExactValue_Procedure:
|
case ExactValue_Procedure:
|
||||||
return hash_pointer(v.value_procedure);
|
return hash_pointer(v.value_procedure);
|
||||||
|
case ExactValue_Typeid:
|
||||||
|
return hash_pointer(v.value_typeid);
|
||||||
}
|
}
|
||||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
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 exact_value_integer_from_string(String const &string) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
big_int_from_string(&result.value_integer, string);
|
big_int_from_string(&result.value_integer, string);
|
||||||
@@ -889,6 +900,13 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
}
|
}
|
||||||
break;
|
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");
|
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);
|
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);
|
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: {
|
case Token_typeid: {
|
||||||
Token token = expect_token(f, 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);
|
return ast_typeid_type(f, token, nullptr);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user