Browse Source

Correct purely named argument handling

gingerBill 2 years ago
parent
commit
09f366bec7
2 changed files with 99 additions and 332 deletions
  1. 97 84
      src/check_expr.cpp
  2. 2 248
      src/llvm_backend_proc.cpp

+ 97 - 84
src/check_expr.cpp

@@ -676,6 +676,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
 								return 1;
 							}
 							break;
+						case Basic_UntypedString:
+							if (is_type_string(dst)) {
+								return 1;
+							}
+							break;
 						case Basic_UntypedFloat:
 							if (is_type_float(dst)) {
 								return 1;
@@ -701,33 +706,48 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
 				return -1;
 			}
 			if (src->kind == Type_Basic) {
+				i64 score = -1;
 				switch (src->Basic.kind) {
 				case Basic_UntypedRune:
 					if (is_type_integer(dst) || is_type_rune(dst)) {
-						if (is_type_typed(type)) {
-							return 2;
-						}
-						return 1;
+						score = 1;
 					}
-					return -1;
-				case Basic_UntypedBool:
-					if (is_type_boolean(dst)) {
-						if (is_type_typed(type)) {
-							return 2;
-						}
-						return 1;
+					break;
+				case Basic_UntypedInteger:
+					if (is_type_integer(dst) || is_type_rune(dst)) {
+						score = 1;
 					}
-					return -1;
+					break;
 				case Basic_UntypedString:
-					if (is_type_string(dst) || is_type_cstring(dst)) {
-						if (is_type_typed(type)) {
-							return 2;
-						}
-						return 1;
+					if (is_type_string(dst)) {
+						score = 1;
 					}
-					return -1;
+					break;
+				case Basic_UntypedFloat:
+					if (is_type_float(dst)) {
+						score = 1;
+					}
+					break;
+				case Basic_UntypedComplex:
+					if (is_type_complex(dst)) {
+						score = 1;
+					}
+					if (is_type_quaternion(dst)) {
+						score = 2;
+					}
+					break;
+				case Basic_UntypedQuaternion:
+					if (is_type_quaternion(dst)) {
+						score = 1;
+					}
+					break;
 				}
-
+				if (score > 0) {
+					if (is_type_typed(dst)) {
+						score += 1;
+					}
+				}
+				return score;
 			}
 		}
 	}
@@ -5447,14 +5467,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 				err = CallArgumentError_DuplicateParameter;
 				continue;
 			}
-			Entity *e = pt->params->Tuple.variables[param_index];
-
-			check_assignment(c, &operand, e->type, str_lit("named argument"));
 
 			visited[param_index] = true;
 			ordered_operands[param_index] = operand;
-
-			err = CallArgumentError_DuplicateParameter;
 		}
 	}
 
@@ -5469,7 +5484,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 				error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name));
 			}
 			err = CallArgumentError_DuplicateParameter;
-		} else {
+		} else if (!visited[pt->variadic_index]) {
 			visited[pt->variadic_index] = true;
 
 			Operand *variadic_operand = &ordered_operands[pt->variadic_index];
@@ -5548,6 +5563,52 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 		}
 	}
 
+	auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error) -> i64 {
+		i64 s = 0;
+		if (!check_is_assignable_to_with_score(c, o, param_type, &s, param_is_variadic)) {
+			bool ok = false;
+			if (e && e->flags & EntityFlag_AnyInt) {
+				if (is_type_integer(param_type)) {
+					ok = check_is_castable_to(c, o, param_type);
+				}
+			}
+			if (ok) {
+				s = assign_score_function(MAXIMUM_TYPE_DISTANCE);
+			} else {
+				if (show_error) {
+					check_assignment(c, o, param_type, str_lit("procedure argument"));
+				}
+				err = CallArgumentError_WrongTypes;
+			}
+
+		} else if (show_error) {
+			check_assignment(c, o, param_type, str_lit("procedure argument"));
+		}
+
+		if (e && e->flags & EntityFlag_ConstInput) {
+			if (o->mode != Addressing_Constant) {
+				if (show_error) {
+					error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string));
+				}
+				err = CallArgumentError_NoneConstantParameter;
+			}
+		}
+
+
+		if (!err && is_type_any(param_type)) {
+			add_type_info_type(c, o->type);
+		}
+		if (o->mode == Addressing_Type && is_type_typeid(param_type)) {
+			add_type_info_type(c, o->type);
+			add_type_and_value(c, o->expr, Addressing_Value, param_type, exact_value_typeid(o->type));
+		} else if (show_error && is_type_untyped(o->type)) {
+			update_untyped_expr_type(c, o->expr, param_type, true);
+		}
+
+		return s;
+	};
+
+
 	if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) {
 		err = CallArgumentError_None;
 
@@ -5555,7 +5616,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 			GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0);
 			Type *t = pt->params->Tuple.variables[0]->type;
 			if (is_type_polymorphic(t)) {
-				error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input");
+				if (show_error) {
+					error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input");
+				}
 				err = CallArgumentError_AmbiguousPolymorphicVariadic;
 			}
 		}
@@ -5596,46 +5659,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 				} else {
 					score += assign_score_function(MAXIMUM_TYPE_DISTANCE);
 				}
-			} else {
-				i64 s = 0;
-				if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) {
-					bool ok = false;
-					if (e->flags & EntityFlag_AnyInt) {
-						if (is_type_integer(e->type)) {
-							ok = check_is_castable_to(c, o, e->type);
-						}
-					}
-					if (ok) {
-						s = assign_score_function(MAXIMUM_TYPE_DISTANCE);
-					} else {
-						if (show_error) {
-							check_assignment(c, o, e->type, str_lit("procedure argument"));
-						}
-						err = CallArgumentError_WrongTypes;
-					}
-
-					if (e->flags & EntityFlag_ConstInput) {
-						if (o->mode != Addressing_Constant) {
-							if (show_error) {
-								error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string));
-							}
-							err = CallArgumentError_NoneConstantParameter;
-						}
-					}
-				} else if (show_error) {
-					check_assignment(c, o, e->type, str_lit("procedure argument"));
-				}
-				if (!param_is_variadic) {
-					score += s;
-				}
+				continue;
 			}
 
-			if (o->mode == Addressing_Type && is_type_typeid(e->type)) {
-				add_type_info_type(c, o->type);
-				add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type));
-			} else if (show_error && is_type_untyped(o->type)) {
-				update_untyped_expr_type(c, o->expr, e->type, true);
+			if (param_is_variadic) {
+				continue;
 			}
+
+			score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error);
 		}
 	}
 
@@ -5651,12 +5682,12 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 		}
 
 		for_array(operand_index, variadic_operands) {
-			Operand &o = variadic_operands[operand_index];
+			Operand *o = &variadic_operands[operand_index];
 			if (vari_expand) {
 				t = slice;
 				if (operand_index > 0) {
 					if (show_error) {
-						error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end");
+						error(o->expr, "'..' in a variadic procedure can only have one variadic argument at the end");
 					}
 					if (data) {
 						data->score = score;
@@ -5666,25 +5697,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 					return CallArgumentError_MultipleVariadicExpand;
 				}
 			}
-			i64 s = 0;
-			if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) {
-				if (show_error) {
-					check_assignment(c, &o, t, str_lit("variadic argument"));
-				}
-				err = CallArgumentError_WrongTypes;
-			} else if (show_error) {
-				check_assignment(c, &o, t, str_lit("variadic argument"));
-			}
-			score += s;
-			if (is_type_any(elem)) {
-				add_type_info_type(c, o.type);
-			}
-			if (o.mode == Addressing_Type && is_type_typeid(t)) {
-				add_type_info_type(c, o.type);
-				add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type));
-			} else if (show_error && is_type_untyped(o.type)) {
-				update_untyped_expr_type(c, o.expr, t, true);
-			}
+			score += eval_param_and_score(c, o, t, err, true, nullptr, show_error);
 		}
 	}
 

+ 2 - 248
src/llvm_backend_proc.cpp

@@ -3336,253 +3336,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
 	GB_ASSERT(proc_type_->kind == Type_Proc);
 	TypeProc *pt = &proc_type_->Proc;
 
-	if (ce->split_args)  {
-		return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args);
-	}
-
-	if (is_call_expr_field_value(ce)) {
-		auto args = array_make<lbValue>(permanent_allocator(), pt->param_count);
-
-		for_array(arg_index, ce->args) {
-			Ast *arg = ce->args[arg_index];
-			ast_node(fv, FieldValue, arg);
-			GB_ASSERT(fv->field->kind == Ast_Ident);
-			String name = fv->field->Ident.token.string;
-			isize index = lookup_procedure_parameter(pt, name);
-			GB_ASSERT(index >= 0);
-			TypeAndValue tav = type_and_value_of_expr(fv->value);
-			if (tav.mode == Addressing_Type) {
-				args[index] = lb_const_nil(m, tav.type);
-			} else {
-				args[index] = lb_build_expr(p, fv->value);
-			}
-		}
-		TypeTuple *params = &pt->params->Tuple;
-		for (isize i = 0; i < args.count; i++) {
-			Entity *e = params->variables[i];
-			if (e->kind == Entity_TypeName) {
-				args[i] = lb_const_nil(m, e->type);
-			} else if (e->kind == Entity_Constant) {
-				continue;
-			} else {
-				GB_ASSERT(e->kind == Entity_Variable);
-				if (args[i].value == nullptr) {
-					args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
-				} else if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
-					args[i] = lb_typeid(p->module, args[i].type);
-				} else {
-					args[i] = lb_emit_conv(p, args[i], e->type);
-				}
-			}
-		}
-
-		for (isize i = 0; i < args.count; i++) {
-			Entity *e = params->variables[i];
-			if (args[i].type == nullptr) {
-				continue;
-			} else if (is_type_untyped_uninit(args[i].type)) {
-				args[i] = lb_const_undef(m, e->type);
-			} else if (is_type_untyped_nil(args[i].type)) {
-				args[i] = lb_const_nil(m, e->type);
-			}
-		}
-
-		return lb_emit_call(p, value, args, ce->inlining);
-	}
-
-	isize arg_index = 0;
-
-	isize arg_count = 0;
-	for_array(i, ce->args) {
-		Ast *arg = ce->args[i];
-		if (arg->kind == Ast_FieldValue) {
-			arg = arg->FieldValue.value;
-		}
-		TypeAndValue tav = type_and_value_of_expr(arg);
-		GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s %d", expr_to_string(arg), expr_to_string(expr), tav.mode);
-		GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
-		Type *at = tav.type;
-		if (is_type_tuple(at)) {
-			arg_count += at->Tuple.variables.count;
-		} else {
-			arg_count++;
-		}
-	}
-
-	isize param_count = 0;
-	if (pt->params) {
-		GB_ASSERT(pt->params->kind == Type_Tuple);
-		param_count = pt->params->Tuple.variables.count;
-	}
-
-	auto args = array_make<lbValue>(permanent_allocator(), cast(isize)gb_max(param_count, arg_count));
-	isize variadic_index = pt->variadic_index;
-	bool variadic = pt->variadic && variadic_index >= 0;
-	bool vari_expand = ce->ellipsis.pos.line != 0;
-	bool is_c_vararg = pt->c_vararg;
-
-	String proc_name = {};
-	if (p->entity != nullptr) {
-		proc_name = p->entity->token.string;
-	}
-	TokenPos pos = ast_token(ce->proc).pos;
-
-	TypeTuple *param_tuple = nullptr;
-	if (pt->params) {
-		GB_ASSERT(pt->params->kind == Type_Tuple);
-		param_tuple = &pt->params->Tuple;
-	}
-
-	for_array(i, ce->args) {
-		Ast *arg = ce->args[i];
-		TypeAndValue arg_tv = type_and_value_of_expr(arg);
-		if (arg_tv.mode == Addressing_Type) {
-			args[arg_index++] = lb_const_nil(m, arg_tv.type);
-		} else {
-			lbValue a = lb_build_expr(p, arg);
-			Type *at = a.type;
-			if (at->kind == Type_Tuple) {
-				lbTupleFix *tf = map_get(&p->tuple_fix_map, a.value);
-				if (tf) {
-					for_array(j, tf->values) {
-						args[arg_index++] = tf->values[j];
-					}
-				} else {
-					for_array(j, at->Tuple.variables) {
-						lbValue v = lb_emit_struct_ev(p, a, cast(i32)j);
-						args[arg_index++] = v;
-					}
-				}
-			} else {
-				args[arg_index++] = a;
-			}
-		}
-	}
-
-
-	if (param_count > 0) {
-		GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
-		GB_ASSERT(param_count < 1000000);
-
-		if (arg_count < param_count) {
-			isize end = cast(isize)param_count;
-			if (variadic) {
-				end = variadic_index;
-			}
-			while (arg_index < end) {
-				Entity *e = param_tuple->variables[arg_index];
-				GB_ASSERT(e->kind == Entity_Variable);
-				args[arg_index++] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
-			}
-		}
-
-		if (is_c_vararg) {
-			GB_ASSERT(variadic);
-			GB_ASSERT(!vari_expand);
-			isize i = 0;
-			for (; i < variadic_index; i++) {
-				Entity *e = param_tuple->variables[i];
-				if (e->kind == Entity_Variable) {
-					args[i] = lb_emit_conv(p, args[i], e->type);
-				}
-			}
-			Type *variadic_type = param_tuple->variables[i]->type;
-			GB_ASSERT(is_type_slice(variadic_type));
-			variadic_type = base_type(variadic_type)->Slice.elem;
-			if (!is_type_any(variadic_type)) {
-				for (; i < arg_count; i++) {
-					args[i] = lb_emit_conv(p, args[i], variadic_type);
-				}
-			} else {
-				for (; i < arg_count; i++) {
-					args[i] = lb_emit_conv(p, args[i], default_type(args[i].type));
-				}
-			}
-		} else if (variadic) {
-			isize i = 0;
-			for (; i < variadic_index; i++) {
-				Entity *e = param_tuple->variables[i];
-				if (e->kind == Entity_Variable) {
-					args[i] = lb_emit_conv(p, args[i], e->type);
-				}
-			}
-			if (!vari_expand) {
-				Type *variadic_type = param_tuple->variables[i]->type;
-				GB_ASSERT(is_type_slice(variadic_type));
-				variadic_type = base_type(variadic_type)->Slice.elem;
-				for (; i < arg_count; i++) {
-					args[i] = lb_emit_conv(p, args[i], variadic_type);
-				}
-			}
-		} else {
-			for (isize i = 0; i < param_count; i++) {
-				Entity *e = param_tuple->variables[i];
-				if (e->kind == Entity_Variable) {
-					if (args[i].value == nullptr) {
-						continue;
-					}
-					GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string));
-					if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
-						GB_ASSERT(LLVMIsNull(args[i].value));
-						args[i] = lb_typeid(p->module, args[i].type);
-					} else {
-						args[i] = lb_emit_conv(p, args[i], e->type);
-					}
-				}
-			}
-		}
-
-		if (variadic && !vari_expand && !is_c_vararg) {
-			// variadic call argument generation
-			Type *slice_type = param_tuple->variables[variadic_index]->type;
-			Type *elem_type  = base_type(slice_type)->Slice.elem;
-			lbAddr slice = lb_add_local_generated(p, slice_type, true);
-			isize slice_len = arg_count+1 - (variadic_index+1);
-
-			if (slice_len > 0) {
-				lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true);
-
-				for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
-					lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)j);
-					lb_emit_store(p, addr, args[i]);
-				}
-
-				lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0);
-				lbValue len = lb_const_int(m, t_int, slice_len);
-				lb_fill_slice(p, slice, base_elem, len);
-			}
-
-			arg_count = param_count;
-			args[variadic_index] = lb_addr_load(p, slice);
-		}
-	}
-
-	if (variadic && variadic_index+1 < param_count) {
-		for (isize i = variadic_index+1; i < param_count; i++) {
-			Entity *e = param_tuple->variables[i];
-			args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
-		}
-	}
-
-	isize final_count = param_count;
-	if (is_c_vararg) {
-		final_count = arg_count;
-	}
-
-	if (param_tuple != nullptr) {
-		for (isize i = 0; i < gb_min(args.count, param_tuple->variables.count); i++) {
-			Entity *e = param_tuple->variables[i];
-			if (args[i].type == nullptr) {
-				continue;
-			} else if (is_type_untyped_uninit(args[i].type)) {
-				args[i] = lb_const_undef(m, e->type);
-			} else if (is_type_untyped_nil(args[i].type)) {
-				args[i] = lb_const_nil(m, e->type);
-			}
-		}
-	}
-
-	auto call_args = array_slice(args, 0, final_count);
-	return lb_emit_call(p, value, call_args, ce->inlining);
+	GB_ASSERT(ce->split_args != nullptr);
+	return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args);
 }