Browse Source

Refactor record polymorphic params code for unification

gingerBill 4 years ago
parent
commit
342761e83a
2 changed files with 58 additions and 60 deletions
  1. 2 1
      src/check_expr.cpp
  2. 56 59
      src/check_type.cpp

+ 2 - 1
src/check_expr.cpp

@@ -5915,7 +5915,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			i32 i = id - cast(i32)BuiltinProc__type_simple_boolean_begin;
 			i32 i = id - cast(i32)BuiltinProc__type_simple_boolean_begin;
 			auto procedure = builtin_type_is_procs[i];
 			auto procedure = builtin_type_is_procs[i];
 			GB_ASSERT_MSG(procedure != nullptr, "%.*s", LIT(builtin_name));
 			GB_ASSERT_MSG(procedure != nullptr, "%.*s", LIT(builtin_name));
-			operand->value = exact_value_bool(procedure(operand->type));
+			bool ok = procedure(operand->type);
+			operand->value = exact_value_bool(ok);
 		}
 		}
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		operand->type = t_untyped_bool;
 		operand->type = t_untyped_bool;

+ 56 - 59
src/check_type.cpp

@@ -338,12 +338,17 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
 }
 }
 
 
 Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
 Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
-                                      bool *is_polymorphic_, bool *can_check_fields_,
+                                      bool *is_polymorphic_,
                                       Ast *node, Array<Operand> *poly_operands,
                                       Ast *node, Array<Operand> *poly_operands,
                                       Type *named_type, Type *original_type_for_poly) {
                                       Type *named_type, Type *original_type_for_poly) {
 	Type *polymorphic_params_type = nullptr;
 	Type *polymorphic_params_type = nullptr;
+	bool can_check_fields = true;
+	GB_ASSERT(is_polymorphic_ != nullptr);
 
 
 	if (polymorphic_params == nullptr) {
 	if (polymorphic_params == nullptr) {
+		if (!*is_polymorphic_) {
+			*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
+		}
 		return polymorphic_params_type;
 		return polymorphic_params_type;
 	}
 	}
 
 
@@ -463,7 +468,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
 					if (is_type_param) {
 					if (is_type_param) {
 						if (is_type_polymorphic(base_type(operand.type))) {
 						if (is_type_polymorphic(base_type(operand.type))) {
 							*is_polymorphic_ = true;
 							*is_polymorphic_ = true;
-							*can_check_fields_ = false;
+							can_check_fields = false;
 						}
 						}
 						e = alloc_entity_type_name(scope, token, operand.type);
 						e = alloc_entity_type_name(scope, token, operand.type);
 						e->TypeName.is_type_alias = true;
 						e->TypeName.is_type_alias = true;
@@ -471,7 +476,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
 					} else {
 					} else {
 						if (is_type_polymorphic(base_type(operand.type))) {
 						if (is_type_polymorphic(base_type(operand.type))) {
 							*is_polymorphic_ = true;
 							*is_polymorphic_ = true;
-							*can_check_fields_ = false;
+							can_check_fields = false;
 						}
 						}
 						if (e == nullptr) {
 						if (e == nullptr) {
 							e = alloc_entity_constant(scope, token, operand.type, operand.value);
 							e = alloc_entity_constant(scope, token, operand.type, operand.value);
@@ -507,9 +512,42 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
 		add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
 		add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
 	}
 	}
 
 
+	if (!*is_polymorphic_) {
+		*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
+	}
+
 	return polymorphic_params_type;
 	return polymorphic_params_type;
 }
 }
 
 
+bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array<Operand> *poly_operands, bool *is_polymorphic_) {
+	if (poly_operands == nullptr) {
+		return false;
+	}
+	for (isize i = 0; i < poly_operands->count; i++) {
+		Operand o = (*poly_operands)[i];
+		if (is_type_polymorphic(o.type)) {
+			return false;
+		}
+		if (record_type == o.type) {
+			// NOTE(bill): Cycle
+			return false;
+		}
+		if (o.mode == Addressing_Type) {
+			// NOTE(bill): ANNOYING EDGE CASE FOR `where` clauses
+			// TODO(bill, 2021-03-27): Is this even a valid HACK?!
+			Entity *entity = entity_of_node(o.expr);
+			if (entity != nullptr &&
+			    entity->kind == Entity_TypeName &&
+			    entity->type == t_typeid) {
+			    	*is_polymorphic_ = true;
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+
 void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
 void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
 	GB_ASSERT(is_type_struct(struct_type));
 	GB_ASSERT(is_type_struct(struct_type));
 	ast_node(st, StructType, node);
 	ast_node(st, StructType, node);
@@ -541,39 +579,18 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 	bool &is_polymorphic = struct_type->Struct.is_polymorphic;
 	bool &is_polymorphic = struct_type->Struct.is_polymorphic;
 
 
 	Type *polymorphic_params = nullptr;
 	Type *polymorphic_params = nullptr;
-	bool can_check_fields    = true;
-	bool is_poly_specialized = false;
 
 
 	polymorphic_params = check_record_polymorphic_params(
 	polymorphic_params = check_record_polymorphic_params(
 		ctx, st->polymorphic_params,
 		ctx, st->polymorphic_params,
-		&is_polymorphic, &can_check_fields,
+		&is_polymorphic,
 		node, poly_operands,
 		node, poly_operands,
 		named_type, original_type_for_poly
 		named_type, original_type_for_poly
 	);
 	);
 
 
-	if (!is_polymorphic) {
-		is_polymorphic = polymorphic_params != nullptr && poly_operands == nullptr;
-	}
-	if (poly_operands != nullptr) {
-		is_poly_specialized = true;
-		for (isize i = 0; i < poly_operands->count; i++) {
-			Operand o = (*poly_operands)[i];
-			if (is_type_polymorphic(o.type)) {
-				is_poly_specialized = false;
-				break;
-			}
-			if (struct_type == o.type) {
-				// NOTE(bill): Cycle
-				is_poly_specialized = false;
-				break;
-			}
-		}
-	}
-
-	struct_type->Struct.scope                   = ctx->scope;
-	struct_type->Struct.is_packed               = st->is_packed;
-	struct_type->Struct.polymorphic_params      = polymorphic_params;
-	struct_type->Struct.is_poly_specialized     = is_poly_specialized;
+	struct_type->Struct.scope               = ctx->scope;
+	struct_type->Struct.is_packed           = st->is_packed;
+	struct_type->Struct.polymorphic_params  = polymorphic_params;
+	struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &is_polymorphic);
 
 
 	if (!is_polymorphic) {
 	if (!is_polymorphic) {
 		if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
 		if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
@@ -611,46 +628,26 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
 	bool &is_polymorphic = union_type->Union.is_polymorphic;
 	bool &is_polymorphic = union_type->Union.is_polymorphic;
 
 
 	Type *polymorphic_params = nullptr;
 	Type *polymorphic_params = nullptr;
-	bool can_check_fields    = true;
-	bool is_poly_specialized = false;
-
 	polymorphic_params = check_record_polymorphic_params(
 	polymorphic_params = check_record_polymorphic_params(
 		ctx, ut->polymorphic_params,
 		ctx, ut->polymorphic_params,
-		&is_polymorphic, &can_check_fields,
+		&is_polymorphic,
 		node, poly_operands,
 		node, poly_operands,
 		named_type, original_type_for_poly
 		named_type, original_type_for_poly
 	);
 	);
 
 
+	union_type->Union.scope                = ctx->scope;
+	union_type->Union.polymorphic_params   = polymorphic_params;
+	union_type->Union.is_polymorphic       = is_polymorphic;
+	union_type->Union.is_poly_specialized  = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &is_polymorphic);
+
 	if (!is_polymorphic) {
 	if (!is_polymorphic) {
-		is_polymorphic = polymorphic_params != nullptr && poly_operands == nullptr;
-	}
-	if (poly_operands != nullptr) {
-		is_poly_specialized = true;
-		for (isize i = 0; i < poly_operands->count; i++) {
-			Operand o = (*poly_operands)[i];
-			if (is_type_polymorphic(o.type)) {
-				is_poly_specialized = false;
-				break;
-			}
-			if (union_type == o.type) {
-				// NOTE(bill): Cycle
-				is_poly_specialized = false;
-				break;
-			}
+		if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
+			error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
+		} else {
+			bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &ut->where_clauses, true);
 		}
 		}
 	}
 	}
 
 
-	union_type->Union.scope                   = ctx->scope;
-	union_type->Union.polymorphic_params      = polymorphic_params;
-	union_type->Union.is_polymorphic          = is_polymorphic;
-	union_type->Union.is_poly_specialized     = is_poly_specialized;
-
-	if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
-		error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
-	} else {
-		bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &ut->where_clauses, true);
-	}
-
 
 
 	for_array(i, ut->variants) {
 	for_array(i, ut->variants) {
 		Ast *node = ut->variants[i];
 		Ast *node = ut->variants[i];