Browse Source

Fix is_type_polymorphic infinite recursion bug

gingerBill 6 years ago
parent
commit
6ab6447791
3 changed files with 36 additions and 27 deletions
  1. 10 7
      src/check_type.cpp
  2. 4 2
      src/ir.cpp
  3. 22 18
      src/types.cpp

+ 10 - 7
src/check_type.cpp

@@ -108,10 +108,11 @@ bool does_field_type_allow_using(Type *t) {
 }
 
 void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const &params,
-                         isize init_field_capacity, Type *named_type, String context) {
+                         isize init_field_capacity, Type *struct_type, String context) {
 	*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
 
 	GB_ASSERT(node->kind == Ast_StructType);
+	GB_ASSERT(struct_type->kind == Type_Struct);
 
 	isize variable_count = 0;
 	for_array(i, params) {
@@ -137,6 +138,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
 		if (type_expr != nullptr) {
 			type = check_type_expr(ctx, type_expr, nullptr);
 			if (is_type_polymorphic(type)) {
+				struct_type->Struct.is_polymorphic = true;
 				type = nullptr;
 			}
 		}
@@ -336,10 +338,12 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 		context = str_lit("struct #raw_union");
 	}
 
-	Type *polymorphic_params     = nullptr;
-	bool is_polymorphic          = false;
-	bool can_check_fields        = true;
-	bool is_poly_specialized     = false;
+	// NOTE(bill): Yes I know it's a non-const reference, what you gonna do?
+	bool &is_polymorphic = struct_type->Struct.is_polymorphic;
+
+	Type *polymorphic_params = nullptr;
+	bool can_check_fields    = true;
+	bool is_poly_specialized = false;
 
 	if (st->polymorphic_params != nullptr) {
 		ast_node(field_list, FieldList, st->polymorphic_params);
@@ -489,12 +493,11 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 	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_polymorphic          = is_polymorphic;
 	struct_type->Struct.is_poly_specialized     = is_poly_specialized;
 
 
 	if (!is_polymorphic) {
-		check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, named_type, context);
+		check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context);
 	}
 
 	if (st->align != nullptr) {

+ 4 - 2
src/ir.cpp

@@ -5163,7 +5163,7 @@ String ir_mangle_name(irGen *s, Entity *e) {
 
 
 	isize max_len = pkgn.len + 1 + name.len + 1;
-	bool require_suffix_id = is_type_polymorphic(e->type);
+	bool require_suffix_id = is_type_polymorphic(e->type, true);
 	if (require_suffix_id) {
 		max_len += 21;
 	}
@@ -5192,7 +5192,7 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) {
 
 	String cn = field->token.string;
 	isize max_len = parent.len + 1 + 16 + 1 + cn.len;
-	bool require_suffix_id = is_type_polymorphic(field->type);
+	bool require_suffix_id = is_type_polymorphic(field->type, true);
 	if (require_suffix_id) {
 		max_len += 21;
 	}
@@ -5325,6 +5325,8 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
 					ir_mangle_add_sub_type_name(m, sub, name);
 				}
 			}
+		} else {
+			GB_PANIC("Unknown poly type %s %p", type_to_string(e->type), e);
 		}
 		return;
 	}

+ 22 - 18
src/types.cpp

@@ -1120,30 +1120,30 @@ TypeTuple *get_record_polymorphic_params(Type *t) {
 }
 
 
-bool is_type_polymorphic(Type *t) {
+bool is_type_polymorphic(Type *t, bool or_specialized=false) {
 	switch (t->kind) {
 	case Type_Generic:
 		return true;
 
 	case Type_Named:
-		return is_type_polymorphic(t->Named.base);
+		return is_type_polymorphic(t->Named.base, or_specialized);
 	case Type_Opaque:
-		return is_type_polymorphic(t->Opaque.elem);
+		return is_type_polymorphic(t->Opaque.elem, or_specialized);
 	case Type_Pointer:
-		return is_type_polymorphic(t->Pointer.elem);
+		return is_type_polymorphic(t->Pointer.elem, or_specialized);
 	case Type_Array:
 		if (t->Array.generic_count != nullptr) {
 			return true;
 		}
-		return is_type_polymorphic(t->Array.elem);
+		return is_type_polymorphic(t->Array.elem, or_specialized);
 	case Type_DynamicArray:
-		return is_type_polymorphic(t->DynamicArray.elem);
+		return is_type_polymorphic(t->DynamicArray.elem, or_specialized);
 	case Type_Slice:
-		return is_type_polymorphic(t->Slice.elem);
+		return is_type_polymorphic(t->Slice.elem, or_specialized);
 
 	case Type_Tuple:
 		for_array(i, t->Tuple.variables) {
-			if (is_type_polymorphic(t->Tuple.variables[i]->type)) {
+			if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) {
 				return true;
 			}
 		}
@@ -1155,11 +1155,11 @@ bool is_type_polymorphic(Type *t) {
 		}
 		#if 1
 		if (t->Proc.param_count > 0 &&
-		    is_type_polymorphic(t->Proc.params)) {
+		    is_type_polymorphic(t->Proc.params, or_specialized)) {
 			return true;
 		}
 		if (t->Proc.result_count > 0 &&
-		    is_type_polymorphic(t->Proc.results)) {
+		    is_type_polymorphic(t->Proc.results, or_specialized)) {
 			return true;
 		}
 		#endif
@@ -1168,14 +1168,20 @@ bool is_type_polymorphic(Type *t) {
 	case Type_Enum:
 		if (t->kind == Type_Enum) {
 			if (t->Enum.base_type != nullptr) {
-				return is_type_polymorphic(t->Enum.base_type);
+				return is_type_polymorphic(t->Enum.base_type, or_specialized);
 			}
 			return false;
 		}
 		break;
 	case Type_Union:
+		if (t->Union.is_polymorphic) {
+			return true;
+		}
+		if (or_specialized && t->Union.is_poly_specialized) {
+			return true;
+		}
 		for_array(i, t->Union.variants) {
-		    if (is_type_polymorphic(t->Union.variants[i])) {
+		    if (is_type_polymorphic(t->Union.variants[i], or_specialized)) {
 		    	return true;
 		    }
 		}
@@ -1184,18 +1190,16 @@ bool is_type_polymorphic(Type *t) {
 		if (t->Struct.is_polymorphic) {
 			return true;
 		}
-		for_array(i, t->Struct.fields) {
-		    if (is_type_polymorphic(t->Struct.fields[i]->type)) {
-		    	return true;
-		    }
+		if (or_specialized && t->Struct.is_poly_specialized) {
+			return true;
 		}
 		break;
 
 	case Type_Map:
-		if (is_type_polymorphic(t->Map.key)) {
+		if (is_type_polymorphic(t->Map.key, or_specialized)) {
 			return true;
 		}
-		if (is_type_polymorphic(t->Map.value)) {
+		if (is_type_polymorphic(t->Map.value, or_specialized)) {
 			return true;
 		}
 		break;