Browse Source

Make `typeid` semantics consistent across variables and constants

gingerBill 5 years ago
parent
commit
6c69e8c043
6 changed files with 113 additions and 45 deletions
  1. 37 17
      src/check_decl.cpp
  2. 47 14
      src/check_expr.cpp
  3. 6 10
      src/checker.cpp
  4. 18 0
      src/exact_value.cpp
  5. 5 0
      src/ir.cpp
  6. 0 4
      src/parser.cpp

+ 37 - 17
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:

+ 47 - 14
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);

+ 6 - 10
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;
 

+ 18 - 0
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");

+ 5 - 0
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);
 	}
 

+ 0 - 4
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;