Browse Source

Fix polymorphic record types with constant value parameters

gingerBill 6 years ago
parent
commit
b7eebe5d00
5 changed files with 82 additions and 26 deletions
  1. 4 14
      src/check_expr.cpp
  2. 56 4
      src/check_type.cpp
  3. 6 3
      src/ir.cpp
  4. 2 1
      src/ir_print.cpp
  5. 14 4
      src/types.cpp

+ 4 - 14
src/check_expr.cpp

@@ -775,6 +775,7 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
 	}
 }
 
+
 bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type) {
 	Operand o = {Addressing_Value};
 	o.type = source;
@@ -985,6 +986,7 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 	o->expr = n;
 	String name = n->Ident.token.string;
 
+
 	Entity *e = scope_lookup(c->scope, name);
 	if (e == nullptr) {
 		if (is_blank_ident(name)) {
@@ -5007,9 +5009,9 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
 			}
 		} else {
 			i64 s = 0;
-			if (is_type_generic(o->type)) {
+			if (o->type->kind == Type_Generic) {
 				// Polymorphic name!
-				score += assign_score_function(0);
+				score += assign_score_function(1);
 				continue;
 			} else if (!check_is_assignable_to_with_score(c, o, e->type, &s)) {
 				if (show_error) {
@@ -5028,18 +5030,6 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
 		}
 	}
 
-	if (param_count < ordered_operands.count) {
-		error(call, "Too many polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
-		err = CallArgumentError_TooManyArguments;
-	} else if (param_count > ordered_operands.count) {
-		error(call, "Too few polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
-		err = CallArgumentError_TooFewArguments;
-	}
-
-	if (err != 0) {
-		return err;
-	}
-
 	{
 		gbAllocator a = c->allocator;
 

+ 56 - 4
src/check_type.cpp

@@ -627,7 +627,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
 							e = alloc_entity_type_name(scope, token, operand.type);
 							e->TypeName.is_type_alias = true;
 						} else {
-							GB_ASSERT(operand.mode == Addressing_Constant);
+							// GB_ASSERT(operand.mode == Addressing_Constant);
 							e = alloc_entity_constant(scope, token, operand.type, operand.value);
 						}
 					} else {
@@ -1117,9 +1117,8 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
 	if (t->kind != s->kind) {
 		return false;
 	}
-	// gb_printf_err("#1 %s %s\n", type_to_string(type), type_to_string(specialization));
-	if (t->kind == Type_Struct) {
 
+	if (t->kind == Type_Struct) {
 		if (t->Struct.polymorphic_parent == specialization) {
 			return true;
 		}
@@ -1136,7 +1135,58 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
 				Entity *t_e = t_tuple->variables[i];
 				Type *st = s_e->type;
 				Type *tt = t_e->type;
-				bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
+
+				// NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types
+				if (st->kind == Type_Generic && t_e->kind == Entity_Constant) {
+					Entity *e = scope_lookup(st->Generic.scope, st->Generic.name);
+					GB_ASSERT(e != nullptr);
+					if (modify_type) {
+						e->kind = Entity_Constant;
+						e->Constant.value = t_e->Constant.value;
+						e->type = t_e->type;
+					}
+				} else {
+					bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
+				}
+			}
+
+			if (modify_type) {
+				// NOTE(bill): This is needed in order to change the actual type but still have the types defined within it
+				gb_memmove(specialization, type, gb_size_of(Type));
+			}
+
+			return true;
+		}
+	} else if (t->kind == Type_Union) {
+		if (t->Union.polymorphic_parent == specialization) {
+			return true;
+		}
+
+		if (t->Union.polymorphic_parent == s->Union.polymorphic_parent &&
+		    s->Union.polymorphic_params != nullptr &&
+		    t->Union.polymorphic_params != nullptr) {
+
+			TypeTuple *s_tuple = &s->Union.polymorphic_params->Tuple;
+			TypeTuple *t_tuple = &t->Union.polymorphic_params->Tuple;
+			GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count);
+			for_array(i, s_tuple->variables) {
+				Entity *s_e = s_tuple->variables[i];
+				Entity *t_e = t_tuple->variables[i];
+				Type *st = s_e->type;
+				Type *tt = t_e->type;
+
+				// NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types
+				if (st->kind == Type_Generic && t_e->kind == Entity_Constant) {
+					Entity *e = scope_lookup(st->Generic.scope, st->Generic.name);
+					GB_ASSERT(e != nullptr);
+					if (modify_type) {
+						e->kind = Entity_Constant;
+						e->Constant.value = t_e->Constant.value;
+						e->type = t_e->type;
+					}
+				} else {
+					bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
+				}
 			}
 
 			if (modify_type) {
@@ -1168,6 +1218,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper
 		}
 		return t_invalid;
 	}
+
 	if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
 		return poly_type;
 	}
@@ -2290,6 +2341,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 				entity_scope = ps;
 			}
 			Entity *e = alloc_entity_type_name(entity_scope, token, t);
+			t->Generic.entity = e;
 			e->TypeName.is_type_alias = true;
 			e->state = EntityState_Resolved;
 			add_entity(ctx->checker, ps, ident, e);

+ 6 - 3
src/ir.cpp

@@ -606,12 +606,14 @@ struct irDebugInfo {
 		} LexicalBlock;
 
 		struct {
+			Type *          type;
 			String          name;
 			i32             size;
 			i32             align;
 			irDebugEncoding encoding;
 		} BasicType;
 		struct {
+			Type *           type;
 			irDebugEncoding  tag;
 			irDebugInfo *    base_type;
 			String           name;
@@ -1766,6 +1768,7 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ
 	// "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependency issues.
 
 	irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType);
+	// GB_ASSERT_MSG(name.len > 0, "%s", type_to_string(type));
 	di->DerivedType.name = name;
 	di->DerivedType.tag = irDebugBasicEncoding_member;
 	di->DerivedType.size = ir_debug_size_bits(type);
@@ -2350,9 +2353,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
 			di->CompositeType.file = file;
 			di->CompositeType.pos = base->Union.node->UnionType.token.pos;
 			for_array(field_index, base->Union.variants) {
-				array_add(&di->CompositeType.elements->DebugInfoArray.elements,
-				          ir_add_debug_info_field(module, di, nullptr, type, cast(i32)field_index,
-				                                  base->Union.variants[field_index], file));
+				// TODO(bill): Union pseudo-"fields"
+				// irDebugInfo *di = ir_add_debug_info_field(module, di, nullptr, type, cast(i32)field_index, base->Union.variants[field_index], file);
+				// array_add(&di->CompositeType.elements->DebugInfoArray.elements, di);
 			}
 		} else if (is_type_enum(type)) {
 			GB_ASSERT(base->kind == Type_Enum);

+ 2 - 1
src/ir_print.cpp

@@ -2437,7 +2437,8 @@ void print_llvm_ir(irGen *ir) {
 			case irDebugInfo_DerivedType: {
 				if (di->DerivedType.tag == irDebugBasicEncoding_member) {
 					// NOTE(lachsinc): We crash llvm super hard if we don't specify a name :)
-					GB_ASSERT(di->DerivedType.name.len > 0);
+					Type *t = di->DerivedType.type;
+					GB_ASSERT_MSG(di->DerivedType.name.len > 0, "%s", type_to_string(di->DerivedType.type));
 				}
 				ir_write_str_lit(f, "!DIDerivedType(tag: ");
 				ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag);

+ 14 - 4
src/types.cpp

@@ -140,10 +140,11 @@ struct TypeUnion {
 		Entity *type_name; /* Entity_TypeName */          \
 	})                                                    \
 	TYPE_KIND(Generic, struct {                           \
-		i64    id;                                        \
-		String name;                                      \
-		Type * specialized;                               \
-		Scope *scope;                                     \
+		i64     id;                                       \
+		String  name;                                     \
+		Type *  specialized;                              \
+		Scope * scope;                                    \
+		Entity *entity;                                   \
 	})                                                    \
 	TYPE_KIND(Pointer, struct { Type *elem; })            \
 	TYPE_KIND(Opaque,  struct { Type *elem; })            \
@@ -1988,6 +1989,15 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 					return sel;
 				}
 			}
+		} else if (type->kind == Type_Union) {
+			Scope *s = type->Union.scope;
+			if (s != nullptr) {
+				Entity *found = scope_lookup_current(s, field_name);
+				if (found != nullptr && found->kind != Entity_Variable) {
+					sel.entity = found;
+					return sel;
+				}
+			}
 		} else if (type->kind == Type_BitSet) {
 			return lookup_field_with_selection(type->BitSet.elem, field_name, true, sel, allow_blank_ident);
 		}