From 18cb8dabd9834ec1e19f0cd7e40bc32689043df6 Mon Sep 17 00:00:00 2001
From: Leo Tenenbaum <pommicket@gmail.com>
Date: Fri, 21 Feb 2020 12:00:00 -0500
Subject: fixed several bugs with struct parameters

---
 err.c    |   2 +-
 eval.c   |  16 +++++++-
 main.c   |   5 ++-
 parse.c  |   2 +
 test.toc |  12 +++++-
 types.c  | 128 ++++++++++++++++++++++++++++++++++++++++++---------------------
 types.h  |   3 +-
 7 files changed, 119 insertions(+), 49 deletions(-)

diff --git a/err.c b/err.c
index 3c2d5d5..0d8c09c 100644
--- a/err.c
+++ b/err.c
@@ -118,7 +118,7 @@ static void err_print_footer_(Location where, bool show_ctx_stack) {
 	print_location_highlight(err_ctx_file(ctx), where);
 	if (ctx && show_ctx_stack) {
 		arr_foreach(ctx->instance_stack, Location, inst) {
-			err_fprint(ctx, "While generating the instance of a function\n\t");
+			err_fprint(ctx, "While generating this instance of a function or struct:\n\t");
 		    print_location_highlight(err_ctx_file(ctx), *inst);
 		}
 	}
diff --git a/eval.c b/eval.c
index 3d72f7b..46d737d 100644
--- a/eval.c
+++ b/eval.c
@@ -741,7 +741,21 @@ static Value *ident_val(Identifier i) {
 	case IDECL_DECL: {
 		Declaration *decl = i->decl;
 		int idx = decl_ident_index(decl, i);
-		if (decl->flags & DECL_IS_CONST)
+		if (decl->flags & DECL_IS_PARAM) {
+			if (decl->val_stack) {
+				Value *valp = *(Value **)arr_last(decl->val_stack);
+				if (arr_len(decl->idents) > 1)
+					return &valp->tuple[idx];
+				else
+					return valp;
+			} else {
+				/* struct parameter */
+				if (arr_len(decl->idents) > 1)
+					return &decl->val.tuple[idx];
+				else
+					return &decl->val;
+			}
+		} else if (decl->flags & DECL_IS_CONST)
 			return decl_val_at_index(decl, idx);
 		else if (decl->val_stack) {
 			Value *valp = *(Value **)arr_last(decl->val_stack);
diff --git a/main.c b/main.c
index 1c6d7d8..5addc27 100644
--- a/main.c
+++ b/main.c
@@ -18,11 +18,14 @@
 
 /* 
 TODO:
-struct parameters
 - make sure inference works with struct params
 - split up a,b::int for parameterized structs (?also maybe normal parameters?)
 - allow accessing parameters with .
 - make call_arg_param_order work more like parameterized_struct_arg_order
+
+- inferred struct params?
+does this work: fn (a::=3, b::=2)
+ - should either work or give an error: fn()
 ---
 see infer.c "is resolved_to necessary" (now that ident system has changed)
 replace is_reference in type_resolve_ with system for checking if type is
diff --git a/parse.c b/parse.c
index 17c9819..206e59a 100644
--- a/parse.c
+++ b/parse.c
@@ -621,6 +621,7 @@ static bool parse_type(Parser *p, Type *type) {
 						err_print(param->where, "Struct parameters must be constant.");
 						goto struct_fail;
 					}
+					param->flags |= DECL_IS_PARAM;
 				}
 			}
 			if (!token_is_kw(t->token, KW_LBRACE)) {
@@ -934,6 +935,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
 				success = false;
 				goto ret;
 			}
+			param->flags |= DECL_IS_PARAM;
 		}
 	}
 	
diff --git a/test.toc b/test.toc
index e115d6b..fcd6119 100644
--- a/test.toc
+++ b/test.toc
@@ -2,10 +2,18 @@
 // #include "std/io.toc";
 // };
 
-Thing ::= struct(t::Type=int) {
+
+
+Thing ::= struct(t::=int, u::t=3) {
    it : t;
+   that : [u]t;
 };
 
 main ::= fn() {
-	 a: Thing();
+	 a: Thing(u = 172, t = u8);
+	 b: Thing();
+	 c : Thing(i16);
+	 d: Thing(u8, 428);
+	 e: Thing(t = int, u = 3);
+	 f: Thing(i16, 3);
 };
\ No newline at end of file
diff --git a/types.c b/types.c
index 28a59c2..1435390 100644
--- a/types.c
+++ b/types.c
@@ -956,8 +956,12 @@ static bool call_arg_param_order(Allocator *allocr, FnExpr *fn, Type *fn_type, A
 	return true;
 }
 
-/* *order must be freed, regardless of return value. if (*order)[i] == -1, that parameter was not set. */
-static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16 **order) {
+/* 
+ *order must be freed, regardless of return value. if (*order)[i] == -1, that parameter was not set.
+*/
+static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16 **order, Location where) {
+	size_t nargs = arr_len(args);
+	
 	/* 
 	   it would be nice if this code and the code for arguments to normal functions
 	   weren't split into two separate functions.
@@ -967,11 +971,16 @@ static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16
 		nparams += arr_len(param->idents);
 
 	*order = err_malloc(nparams * sizeof **order);
+	
+	if (nargs > nparams) {
+		err_print(args[nparams].where, "Expected at most %lu argument%s to parameterized type, but got %lu.", nparams, plural_suffix(nparams), nargs);
+		return false;
+	}
 	for (size_t i = 0; i < nparams; ++i)
 		(*order)[i] = -1;
 	int p = 0; /* sequential parameter */
+	I16 argno = 0;
 	
-
 	arr_foreach(args, Argument, arg) {
 		int param_idx;
 		if (arg->name) {
@@ -1006,8 +1015,23 @@ static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16
 			free(s);
 			return false;
 		}
-	    (*order)[arg - args] = (I16)param_idx;
+	    (*order)[param_idx] = argno;
+		++argno;
+	}
+	
+	p = 0;
+	arr_foreach(struc->params, Declaration, param) {
+		arr_foreach(param->idents, Identifier, ident) {
+			if ((*order)[p] == -1 && !(param->flags & DECL_HAS_EXPR)) {
+				char *s = ident_to_str(*ident);
+				err_print(where, "Parameter #%d (%s) not set in parameterized struct instantiation.", p+1, s);
+				free(s);
+				return false;
+			}
+			++p;
+		}
 	}
+	
 	return true;
 }
 
@@ -1468,6 +1492,8 @@ static bool types_expr(Typer *tr, Expression *e) {
 		
 		if (expr_is_definitely_const(f) || type_is_builtin(&f->type, BUILTIN_TYPE)) {
 			Value val;
+			
+			
 			if (!eval_expr(tr->evalr, f, &val))
 				return false;
 			if (type_is_builtin(&f->type, BUILTIN_TYPE)) {
@@ -1481,65 +1507,76 @@ static bool types_expr(Typer *tr, Expression *e) {
 					info_print(base->struc->where, "struct was declared here.");
 					return false;
 				}
+				Copier cop = copier_create(tr->allocr, tr->block);
+				HashTable *table = &base->struc->instances;
+				StructDef struc;
+				copy_struct(&cop, &struc, base->struc);
 
 				size_t nparams = 0;
-				arr_foreach(base->struc->params, Declaration, param)
+				arr_foreach(struc.params, Declaration, param)
 					nparams += arr_len(param->idents);
-				size_t nargs = arr_len(c->args);
-				if (nargs > nparams) {
-					err_print(e->where, "Expected at most %lu argument%s to parameterized type, but got %lu.", nparams, plural_suffix(nparams), nargs);
-					return false;
-				}
-				HashTable *table = &base->struc->instances;
 				bool already_exists;
 				Value args_val = {0};
 				Type args_type = {0};
 				I16 *order;
-				if (!parameterized_struct_arg_order(base->struc, c->args, &order)) {
+				if (!parameterized_struct_arg_order(&struc, c->args, &order, e->where)) {
 					free(order);
 					return false;
 				}
 				Type *arg_types = NULL;
 				arr_set_len(&arg_types, nparams);
 				Value *arg_vals = typer_malloc(tr, nparams * sizeof *arg_vals);
-				
-				for (size_t i = 0; i < nparams; ++i) {
-					if (order[i] == -1) {
-						Declaration *ith_parameter = NULL; 
-						int index_in_decl = -1;
-						size_t i_copy = i;
-						/* fetch ith parameter */
-						arr_foreach(base->struc->params, Declaration, param) {
-							arr_foreach(param->idents, Identifier, ident) {
-								if (i_copy == 0) {
-									/* here we are */
-									ith_parameter = param;
-									index_in_decl = (int)(ident - param->idents);
-									break;
-								}
-								--i_copy;
+				ErrCtx *err_ctx = tr->err_ctx;
+				size_t p = 0;
+				arr_foreach(struc.params, Declaration, param) {
+					Value param_val = {0};
+					bool is_tuple = arr_len(param->idents) > 1;
+					int ident_idx = 0;
+					/* temporarily add this instance to the stack, while we type the decl, in case you, e.g., pass t = float to struct(t::Type, u::t = "hello") */
+					*(Location *)arr_add(&err_ctx->instance_stack) = e->where;
+					if (!types_decl(tr, param)) {
+						arr_remove_last(&err_ctx->instance_stack);
+						return false;
+					}
+					arr_remove_last(&err_ctx->instance_stack);
+
+					arr_foreach(param->idents, Identifier, ident) {
+						Type *type = decl_type_at_index(param, ident_idx);
+						arg_types[p] = *type;
+						Value ident_val;
+						if (order[p] == -1) {
+						    ident_val = *decl_val_at_index(param, ident_idx);
+						} else {
+							Argument *arg = &c->args[order[p]];
+							assert(arg->val.type.flags & TYPE_IS_RESOLVED);
+							assert(type->flags & TYPE_IS_RESOLVED);
+							if (!type_eq(&arg->val.type, type)) {
+								char *expected = type_to_str(type),
+									*got = type_to_str(&arg->val.type);
+								err_print(arg->where, "Wrong struct parameter type. Expected %s, but got %s.", expected, got);
+								return false;
 							}
+							if (!eval_expr(tr->evalr, &arg->val, &ident_val))
+								return false;
 						}
-						assert(ith_parameter);
-					    arg_types[i] = *decl_type_at_index(ith_parameter, index_in_decl);
-						arg_vals[i] = *decl_val_at_index(ith_parameter, index_in_decl);
-					} else {
-						Argument *arg = &c->args[order[i]];
-						arg_types[i] = arg->val.type;
-						if (!eval_expr(tr->evalr, &arg->val, &arg_vals[i]))
-							return false;
+						if (is_tuple)
+							*(Value *)arr_adda(&param_val.tuple, tr->allocr) = ident_val;
+						else
+							param_val = ident_val;
+						arg_vals[p] = ident_val;
+						++p;
+						++ident_idx;
 					}
-					assert(arg_types[i].flags & TYPE_IS_RESOLVED);
+					param->val = param_val;
+					param->flags |= DECL_FOUND_VAL;
 				}
-				
 				args_val.tuple = arg_vals;
 				args_type.tuple = arg_types;
 				args_type.kind = TYPE_TUPLE;
 				args_type.flags = TYPE_IS_RESOLVED;
 				Instance *inst = instance_table_adda(tr->allocr, table, args_val, &args_type, &already_exists);
 				if (!already_exists) {
-					Copier cop = copier_create(tr->allocr, tr->block);
-					copy_struct(&cop, &inst->struc, base->struc);
+					inst->struc = struc;
 					size_t i = 0;
 					arr_foreach(inst->struc.params, Declaration, param) {
 					    param->flags |= DECL_FOUND_VAL;
@@ -1547,8 +1584,8 @@ static bool types_expr(Typer *tr, Expression *e) {
 							param->val = arg_vals[i];
 							++i;
 						} else {
-							assert(param->type.kind == TYPE_TUPLE);
-							size_t nmembers = arr_len(param->type.tuple);
+
+							size_t nmembers = arr_len(param->idents);
 							param->val.tuple = typer_malloc(tr, nmembers * sizeof *param->val.tuple);
 							for (size_t idx = 0; idx < nmembers; ++idx) {
 								param->val.tuple[idx] = arg_vals[i];
@@ -1560,8 +1597,13 @@ static bool types_expr(Typer *tr, Expression *e) {
 					Type struct_t = {0};
 					struct_t.kind = TYPE_STRUCT;
 					struct_t.struc = &inst->struc;
-					if (!type_resolve(tr, &struct_t, e->where)) /* resolve the struct */
+					*(Location *)arr_add(&err_ctx->instance_stack) = e->where;
+					if (!type_resolve(tr, &struct_t, e->where)) /* resolve the struct */ {
+						arr_remove_last(&err_ctx->instance_stack);
 						return false;
+					}
+				    arr_remove_last(&err_ctx->instance_stack);
+						
 					inst->struc.instance_id = table->n;
 				}
 				/* expression is actually a type */
diff --git a/types.h b/types.h
index e20f03a..18836bf 100644
--- a/types.h
+++ b/types.h
@@ -782,7 +782,8 @@ enum {
 	  DECL_FOUND_VAL = 0x0040,
 	  DECL_INFER = 0x0080, /* infer the value (e.g. fn(t::Type=, x:t)) */
 	  DECL_EXPORT = 0x0100,
-	  DECL_FOREIGN = 0x0200
+	  DECL_FOREIGN = 0x0200,
+	  DECL_IS_PARAM = 0x0400
 };
 
 typedef U16 DeclFlags;
-- 
cgit v1.2.3