소스 검색

Basic polymorphic named procedure parameters for procedures and records

gingerBill 5 년 전
부모
커밋
f229084baa
9개의 변경된 파일165개의 추가작업 그리고 44개의 파일을 삭제
  1. 1 2
      src/check_decl.cpp
  2. 38 29
      src/check_expr.cpp
  3. 16 6
      src/check_type.cpp
  4. 3 0
      src/checker.cpp
  5. 20 0
      src/entity.cpp
  6. 20 2
      src/exact_value.cpp
  7. 30 1
      src/ir.cpp
  8. 34 4
      src/llvm_backend.cpp
  9. 3 0
      src/types.cpp

+ 1 - 2
src/check_decl.cpp

@@ -1193,7 +1193,6 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
 
 							ProcUsingVar puv = {e, uvar};
 							array_add(&using_entities, puv);
-
 						}
 					}
 				} else {
@@ -1221,7 +1220,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
 		// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
 		return;
 	}
-
+	
 	check_open_scope(ctx, body);
 	{
 		for_array(i, using_entities) {

+ 38 - 29
src/check_expr.cpp

@@ -1117,6 +1117,9 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 	e->flags |= EntityFlag_Used;
 
 	Type *type = e->type;
+
+	o->type = type;
+
 	switch (e->kind) {
 	case Entity_Constant:
 		if (type == t_invalid) {
@@ -1127,6 +1130,14 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 		if (o->value.kind == ExactValue_Invalid) {
 			return e;
 		}
+		if (o->value.kind == ExactValue_Procedure) {
+			Entity *proc = strip_entity_wrapping(o->value.value_procedure);
+			if (proc != nullptr) {
+				o->mode = Addressing_Value;
+				o->type = proc->type;
+				return proc;
+			}
+		}
 		o->mode = Addressing_Constant;
 		break;
 
@@ -1144,6 +1155,7 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 
 	case Entity_Procedure:
 		o->mode = Addressing_Value;
+		o->value = exact_value_procedure(n);
 		break;
 
 	case Entity_Builtin:
@@ -1180,7 +1192,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 		break;
 	}
 
-	o->type = type;
 	return e;
 }
 
@@ -3602,10 +3613,20 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
 
 	add_entity_use(c, selector, entity);
 
+	operand->type = entity->type;
+	operand->expr = node;
+
 	switch (entity->kind) {
 	case Entity_Constant:
-		operand->mode = Addressing_Constant;
 		operand->value = entity->Constant.value;
+		operand->mode = Addressing_Constant;
+		if (operand->value.kind == ExactValue_Procedure) { 
+			Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
+			if (proc != nullptr) {
+				operand->mode = Addressing_Value;
+				operand->type = proc->type;
+			}
+		}
 		break;
 	case Entity_Variable:
 		// TODO(bill): Is this the rule I need?
@@ -3628,6 +3649,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
 		break;
 	case Entity_Procedure:
 		operand->mode = Addressing_Value;
+		operand->value = exact_value_procedure(node);
 		break;
 	case Entity_Builtin:
 		operand->mode = Addressing_Builtin;
@@ -3645,8 +3667,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
 		break;
 	}
 
-	operand->type = entity->type;
-	operand->expr = node;
+	add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value);
 
 	return entity;
 }
@@ -7044,10 +7065,17 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
 			}
 			o->type = e->type;
 			if (o->mode != Addressing_Constant) {
-				if (show_error) {
-					error(o->expr, "Expected a constant value for this polymorphic type argument");
+				bool valid = false;
+				if (is_type_proc(o->type)) {
+					Entity *proc_entity = entity_from_expr(o->expr);
+					valid = proc_entity != nullptr;
+				}
+				if (!valid) {
+					if (show_error) {
+						error(o->expr, "Expected a constant value for this polymorphic type argument");
+					}
+					err = CallArgumentError_NoneConstantParameter;
 				}
-				err = CallArgumentError_NoneConstantParameter;
 			}
 			score += s;
 		}
@@ -9257,29 +9285,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 
 ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 	ExprKind kind = check_expr_base_internal(c, o, node, type_hint);
-	Type *type = nullptr;
-	ExactValue value = {ExactValue_Invalid};
-	switch (o->mode) {
-	case Addressing_Invalid:
-		type = t_invalid;
-		break;
-	case Addressing_NoValue:
-		type = nullptr;
-		break;
-	case Addressing_Constant:
-		value = o->value;
-		type = o->type;
-		break;
-	default:
-		type = o->type;
-		break;
+	if (o->type != nullptr && is_type_untyped(o->type)) {
+		add_untyped(&c->checker->info, node, false, o->mode, o->type, o->value);
 	}
-
-	if (type != nullptr && is_type_untyped(type)) {
-		add_untyped(&c->checker->info, node, false, o->mode, type, value);
-	}
-	add_type_and_value(&c->checker->info, node, o->mode, type, value);
-
+	add_type_and_value(&c->checker->info, node, o->mode, o->type, o->value);
 	return kind;
 }
 

+ 16 - 6
src/check_type.cpp

@@ -469,7 +469,9 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 								is_polymorphic = true;
 								can_check_fields = false;
 							}
-							e = alloc_entity_constant(scope, token, operand.type, operand.value);
+							if (e == nullptr) {
+								e = alloc_entity_constant(scope, token, operand.type, operand.value);
+							}
 						}
 					} else {
 						if (is_type_param) {
@@ -1672,11 +1674,19 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
 						}
 					}
 					if (is_poly_name) {
-						if (op.mode == Addressing_Constant) {
-							poly_const = op.value;
-						} else {
-							error(op.expr, "Expected a constant value for this polymorphic name parameter");
-							success = false;
+						bool valid = false;
+						if (is_type_proc(op.type)) {
+							Entity *proc_entity = entity_from_expr(op.expr);
+							valid = proc_entity != nullptr;
+							poly_const = exact_value_procedure(proc_entity->identifier ? proc_entity->identifier : op.expr);
+						}
+						if (!valid) {
+							if (op.mode == Addressing_Constant) {
+								poly_const = op.value;
+							} else {
+								error(op.expr, "Expected a constant value for this polymorphic name parameter");
+								success = false;
+							}
 						}
 					}
 					if (is_type_untyped(default_type(type))) {

+ 3 - 0
src/checker.cpp

@@ -885,6 +885,7 @@ void destroy_checker(Checker *c) {
 
 
 Entity *entity_of_ident(Ast *identifier) {
+	identifier = unparen_expr(identifier);
 	if (identifier->kind == Ast_Ident) {
 		return identifier->Ident.entity;
 	}
@@ -1042,6 +1043,8 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty
 				expr->tav.value = value;
 			} else if (mode == Addressing_Value && is_type_typeid(type)) {
 				expr->tav.value = value;
+			} else if (mode == Addressing_Value && is_type_proc(type)) {
+				expr->tav.value = value;
 			}
 
 			prev_expr = expr;

+ 20 - 0
src/entity.cpp

@@ -357,3 +357,23 @@ Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
 	return alloc_entity_variable(scope, token, nullptr);
 }
 
+
+Entity *entity_from_expr(Ast *expr);
+
+Entity *strip_entity_wrapping(Entity *e) {
+	if (e == nullptr) {
+		return nullptr;
+	}
+	if (e->kind != Entity_Constant) {
+		return e;
+	}
+	if (e->Constant.value.kind == ExactValue_Procedure) {
+		return strip_entity_wrapping(e->Constant.value.value_procedure);
+	}
+	return e;
+}
+
+Entity *strip_entity_wrapping(Ast *expr) {
+	Entity *e = entity_from_expr(expr);
+	return strip_entity_wrapping(e);
+}

+ 20 - 2
src/exact_value.cpp

@@ -592,6 +592,10 @@ i32 exact_value_order(ExactValue const &v) {
 		return 5;
 	case ExactValue_Pointer:
 		return 6;
+	case ExactValue_Procedure:
+		return 7;
+	// case ExactValue_Compound:
+		// return 8;
 
 	default:
 		GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -652,6 +656,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
 			return;
 		}
 		break;
+
+	case ExactValue_Procedure:
+		return;
 	}
 
 	compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
@@ -915,12 +922,23 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
 		case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
 		}
 		break;
+
+	case ExactValue_Procedure:
+		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");
 	return false;
 }
 
+Entity *strip_entity_wrapping(Ast *expr);
+Entity *strip_entity_wrapping(Entity *e);
+
+gbString write_expr_to_string(gbString str, Ast *node);
 
 gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
 	switch (v.kind) {
@@ -956,9 +974,9 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
 	case ExactValue_Pointer:
 		return str;
 	case ExactValue_Compound:
-		return str;
+		return write_expr_to_string(str, v.value_compound);
 	case ExactValue_Procedure:
-		return str;
+		return write_expr_to_string(str, v.value_procedure);
 	}
 	return str;
 };

+ 30 - 1
src/ir.cpp

@@ -1984,7 +1984,11 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
 	// case Basic_f16:
 	case Basic_f32:
 	case Basic_f64:
-		return irDebugBasicEncoding_float;
+	case Basic_f32le:
+	case Basic_f64le:
+	case Basic_f32be:
+	case Basic_f64be:
+			return irDebugBasicEncoding_float;
 
 	// case Basic_complex32:
 	case Basic_complex64:
@@ -7104,6 +7108,29 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
 			return ir_emit_conv(proc, v, tv.type);
 		}
 
+		if (tv.value.kind == ExactValue_Procedure) {
+			Ast *expr = tv.value.value_procedure;
+			if (expr->kind == Ast_ProcLit) {
+				return ir_gen_anonymous_proc_lit(proc->module, str_lit("_proclit"), expr);
+			}
+			Entity *e = entity_from_expr(expr);
+			e = strip_entity_wrapping(e);
+			GB_ASSERT(e != nullptr);
+			auto *found = map_get(&proc->module->values, hash_entity(e));
+			if (found) {
+				auto v = *found;
+				// NOTE(bill): This is because pointers are already pointers in LLVM
+				if (is_type_proc(ir_type(v))) {
+					return v;
+				}
+				return ir_emit_load(proc, v);
+			} else if (e != nullptr && e->kind == Entity_Variable) {
+				return ir_addr_load(proc, ir_build_addr(proc, expr));
+			}
+
+			GB_PANIC("Error in: %.*s(%td:%td) %s\n", LIT(proc->name), e->token.pos.line, e->token.pos.column);
+		}
+
 		return ir_add_module_constant(proc->module, tv.type, tv.value);
 	}
 
@@ -7139,6 +7166,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
 
 	case_ast_node(i, Ident, expr);
 		Entity *e = entity_of_ident(expr);
+		e = strip_entity_wrapping(e);
+
 		GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr));
 		if (e->kind == Entity_Builtin) {
 			Token token = ast_token(expr);

+ 34 - 4
src/llvm_backend.cpp

@@ -8565,6 +8565,30 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 	GB_ASSERT(tv.mode != Addressing_Type);
 
 	if (tv.value.kind != ExactValue_Invalid) {
+		if (tv.value.kind == ExactValue_Procedure) {
+			Ast *expr = tv.value.value_procedure;
+			if (expr->kind == Ast_ProcLit) {
+				return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
+			}
+			Entity *e = entity_from_expr(expr);
+			e = strip_entity_wrapping(e);
+			GB_ASSERT(e != nullptr);
+			auto *found = map_get(&p->module->values, hash_entity(e));
+			if (found) {
+				auto v = *found;
+				// NOTE(bill): This is because pointers are already pointers in LLVM
+				if (is_type_proc(v.type)) {
+					return v;
+				}
+				return lb_emit_load(p, v);
+			} else if (e != nullptr && e->kind == Entity_Variable) {
+				return lb_addr_load(p, lb_build_addr(p, expr));
+			}
+
+			GB_PANIC("Error in: %.*s(%td:%td) %s\n", LIT(p->name), e->token.pos.line, e->token.pos.column);
+			// GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(e->pkg->name), LIT(e->token.string), e, type_to_string(e->type), expr);
+		}
+
 		// NOTE(bill): Short on constant values
 		return lb_const_value(p->module, tv.type, tv.value);
 	}
@@ -8599,7 +8623,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 	case_end;
 
 	case_ast_node(i, Ident, expr);
-		Entity *e = entity_of_ident(expr);
+		Entity *e = entity_from_expr(expr);
+		e = strip_entity_wrapping(e);
+
 		GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr));
 		if (e->kind == Entity_Builtin) {
 			Token token = ast_token(expr);
@@ -8626,8 +8652,12 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
 		} else if (e != nullptr && e->kind == Entity_Variable) {
 			return lb_addr_load(p, lb_build_addr(p, expr));
 		}
-		gb_printf_err("Error in: %.*s(%td:%td)\n", LIT(p->name), i->token.pos.line, i->token.pos.column);
-		GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(e->pkg->name), LIT(e->token.string), e, type_to_string(e->type), expr);
+		gb_printf_err("Error in: %.*s(%td:%td) %s\n", LIT(p->name), i->token.pos.line, i->token.pos.column);
+		String pkg = {};
+		if (e->pkg) {
+			pkg = e->pkg->name;
+		}
+		GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(pkg), LIT(e->token.string), e, type_to_string(e->type), expr);
 		return {};
 	case_end;
 
@@ -9085,7 +9115,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			if (tav.mode == Addressing_Type) { // Addressing_Type
 				Selection sel = lookup_field(type, selector, true);
 				Entity *e = sel.entity;
-				GB_ASSERT(e->kind == Entity_Variable);
+				GB_ASSERT_MSG(e->kind == Entity_Variable, "Entity_%.*s", LIT(entity_strings[e->kind]));
 				GB_ASSERT(e->flags & EntityFlag_TypeField);
 				String name = e->token.string;
 				/*if (name == "names") {

+ 3 - 0
src/types.cpp

@@ -1039,6 +1039,9 @@ bool is_type_constant_type(Type *t) {
 	if (t->kind == Type_BitSet) {
 		return true;
 	}
+	if (t->kind == Type_Proc) {
+		return true;
+	}
 	return false;
 }
 bool is_type_float(Type *t) {