aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-10-06 14:55:25 +0100
committergingerBill <bill@gingerbill.org>2019-10-06 14:55:25 +0100
commit6c69e8c043e7dcf9d9965c7b28c7bdae44e0537c (patch)
treeaf5f3434bcbc20a87e905a4f7646dc958b00ae8d /src
parent7fa2d25eea28955c12d8fc6a597e8615562c0ee9 (diff)
Make `typeid` semantics consistent across variables and constants
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.cpp54
-rw-r--r--src/check_expr.cpp61
-rw-r--r--src/checker.cpp16
-rw-r--r--src/exact_value.cpp18
-rw-r--r--src/ir.cpp5
-rw-r--r--src/parser.cpp4
6 files changed, 113 insertions, 45 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 166b6e715..5e8479a7f 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -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:
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 697abef5f..6a0d8221f 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -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);
diff --git a/src/checker.cpp b/src/checker.cpp
index 994e0776d..f30273439 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -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;
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index fcc6f1973..95d04d93b 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -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");
diff --git a/src/ir.cpp b/src/ir.cpp
index 758267c24..f29d389f4 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -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);
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 204ff3984..fb093ffd9 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -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;