Make typeid semantics consistent across variables and constants

This commit is contained in:
gingerBill
2019-10-06 14:55:25 +01:00
parent 7fa2d25eea
commit 6c69e8c043
6 changed files with 113 additions and 45 deletions
+37 -17
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+18
View File
@@ -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");
+5
View File
@@ -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);
}
-4
View File
@@ -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;