Browse Source

Default procedure values for `proc`

Ginger Bill 8 years ago
parent
commit
afb5538e83
3 changed files with 89 additions and 4 deletions
  1. 71 3
      src/check_expr.cpp
  2. 16 0
      src/ir.cpp
  3. 2 1
      src/types.cpp

+ 71 - 3
src/check_expr.cpp

@@ -1071,7 +1071,26 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
 				if (is_operand_nil(o)) {
 					default_is_nil = true;
 				} else if (o.mode != Addressing_Constant) {
-					error(default_value, "Default parameter must be a constant");
+					if (default_value->kind == AstNode_ProcLit) {
+						value = exact_value_procedure(default_value);
+					} else {
+						Entity *e = nullptr;
+						if (o.mode == Addressing_Value && is_type_proc(o.type)) {
+							Operand x = {};
+							if (default_value->kind == AstNode_Ident) {
+								e = check_ident(c, &x, default_value, nullptr, nullptr, false);
+							} else if (default_value->kind == AstNode_SelectorExpr) {
+								e = check_selector(c, &x, default_value, nullptr);
+							}
+						}
+
+						if (e != nullptr && e->kind == Entity_Procedure) {
+							value = exact_value_procedure(e->identifier);
+							add_entity_use(c, e->identifier, e);
+						} else {
+							error(default_value, "Default parameter must be a constant");
+						}
+					}
 				} else {
 					value = o.value;
 				}
@@ -2132,7 +2151,26 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 				if (is_operand_nil(o)) {
 					default_is_nil = true;
 				} else if (o.mode != Addressing_Constant) {
-					error(default_value, "Default parameter must be a constant");
+					if (default_value->kind == AstNode_ProcLit) {
+						value = exact_value_procedure(default_value);
+					} else {
+						Entity *e = nullptr;
+						if (o.mode == Addressing_Value && is_type_proc(o.type)) {
+							Operand x = {};
+							if (default_value->kind == AstNode_Ident) {
+								e = check_ident(c, &x, default_value, nullptr, nullptr, false);
+							} else if (default_value->kind == AstNode_SelectorExpr) {
+								e = check_selector(c, &x, default_value, nullptr);
+							}
+						}
+
+						if (e != nullptr && e->kind == Entity_Procedure) {
+							value = exact_value_procedure(e->identifier);
+							add_entity_use(c, e->identifier, e);
+						} else {
+							error(default_value, "Default parameter must be a constant");
+						}
+					}
 				} else {
 					value = o.value;
 				}
@@ -2201,7 +2239,26 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 						if (is_operand_nil(o)) {
 							default_is_nil = true;
 						} else if (o.mode != Addressing_Constant) {
-							error(default_value, "Default parameter must be a constant");
+							if (default_value->kind == AstNode_ProcLit) {
+								value = exact_value_procedure(default_value);
+							} else {
+								Entity *e = nullptr;
+								if (o.mode == Addressing_Value && is_type_proc(o.type)) {
+									Operand x = {};
+									if (default_value->kind == AstNode_Ident) {
+										e = check_ident(c, &x, default_value, nullptr, nullptr, false);
+									} else if (default_value->kind == AstNode_SelectorExpr) {
+										e = check_selector(c, &x, default_value, nullptr);
+									}
+								}
+
+								if (e != nullptr && e->kind == Entity_Procedure) {
+									value = exact_value_procedure(e->identifier);
+									add_entity_use(c, e->identifier, e);
+								} else {
+									error(default_value, "Default parameter must be a constant");
+								}
+							}
 						} else {
 							value = o.value;
 						}
@@ -2682,11 +2739,22 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
 	Type *params  = check_get_params(c, c->context.scope, pt->params, &variadic, &success, &specialization_count, operands);
 	Type *results = check_get_results(c, c->context.scope, pt->results);
 
+
 	isize param_count = 0;
 	isize result_count = 0;
 	if (params)  param_count  = params ->Tuple.variables.count;
 	if (results) result_count = results->Tuple.variables.count;
 
+	if (param_count > 0) {
+		for_array(i, params->Tuple.variables) {
+			Entity *param = params->Tuple.variables[i];
+			if (param->kind == Entity_Variable && param->Variable.default_value.kind == ExactValue_Procedure) {
+				type->Proc.has_proc_default_values = true;
+				break;
+			}
+		}
+	}
+
 	type->Proc.node                 = proc_type_node;
 	type->Proc.scope                = c->context.scope;
 	type->Proc.params               = params;

+ 16 - 0
src/ir.cpp

@@ -7422,6 +7422,22 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
 
 		proc->module->stmt_state_flags = prev_stmt_state_flags;
 	}
+
+
+	if (proc->type->Proc.has_proc_default_values) {
+		auto *p = &proc->type->Proc;
+		for_array(i, p->params->Tuple.variables) {
+			Entity *f = p->params->Tuple.variables[i];
+			if (f->kind == Entity_Variable && f->Variable.default_value.kind == ExactValue_Procedure) {
+				AstNode *expr = f->Variable.default_value.value_procedure;
+				GB_ASSERT(expr != nullptr);
+				if (expr->kind == AstNode_ProcLit) {
+					ir_gen_anonymous_proc_lit(proc->module, proc->name, expr, proc);
+				}
+			}
+		}
+	}
+
 }
 
 

+ 2 - 1
src/types.cpp

@@ -139,14 +139,15 @@ struct TypeStruct {
 		Type *   results; /* Type_Tuple */                \
 		i32      param_count;                             \
 		i32      result_count;                            \
-		bool     return_by_pointer;                       \
 		Type **  abi_compat_params;                       \
 		Type *   abi_compat_result_type;                  \
+		bool     return_by_pointer;                       \
 		bool     variadic;                                \
 		bool     require_results;                         \
 		bool     c_vararg;                                \
 		bool     is_polymorphic;                          \
 		bool     is_poly_specialized;                     \
+		bool     has_proc_default_values;                 \
 		isize    specialization_count;                    \
 		ProcCallingConvention calling_convention;         \
 	})                                                    \