Browse Source

Merge pull request #99150 from dalexeev/gds-fix-callable-call-errror-text

GDScript: Fix `Callable` call error text
Thaddeus Crews 2 months ago
parent
commit
86415f1732

+ 1 - 1
core/variant/variant_callable.cpp

@@ -45,7 +45,7 @@ uint32_t VariantCallable::hash() const {
 }
 }
 
 
 String VariantCallable::get_as_text() const {
 String VariantCallable::get_as_text() const {
-	return vformat("%s::%s (Callable)", Variant::get_type_name(variant.get_type()), method);
+	return vformat("%s::%s", Variant::get_type_name(variant.get_type()), method);
 }
 }
 
 
 CallableCustom::CompareEqualFunc VariantCallable::get_compare_equal_func() const {
 CallableCustom::CompareEqualFunc VariantCallable::get_compare_equal_func() const {

+ 2 - 1
modules/gdscript/gdscript_function.h

@@ -551,7 +551,8 @@ private:
 	} profile;
 	} profile;
 #endif
 #endif
 
 
-	_FORCE_INLINE_ String _get_call_error(const String &p_where, const Variant **p_argptrs, const Variant &p_ret, const Callable::CallError &p_err) const;
+	String _get_call_error(const String &p_where, const Variant **p_argptrs, int p_argcount, const Variant &p_ret, const Callable::CallError &p_err) const;
+	String _get_callable_call_error(const String &p_where, const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Variant &p_ret, const Callable::CallError &p_err) const;
 	Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type);
 	Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type);
 
 
 public:
 public:

+ 1 - 1
modules/gdscript/gdscript_utility_callable.cpp

@@ -55,7 +55,7 @@ String GDScriptUtilityCallable::get_as_text() const {
 			scope = "@GDScript";
 			scope = "@GDScript";
 			break;
 			break;
 	}
 	}
-	return vformat("%s::%s (Callable)", scope, function_name);
+	return vformat("%s::%s", scope, function_name);
 }
 }
 
 
 CallableCustom::CompareEqualFunc GDScriptUtilityCallable::get_compare_equal_func() const {
 CallableCustom::CompareEqualFunc GDScriptUtilityCallable::get_compare_equal_func() const {

+ 37 - 10
modules/gdscript/gdscript_vm.cpp

@@ -150,7 +150,7 @@ Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataT
 	return Variant();
 	return Variant();
 }
 }
 
 
-String GDScriptFunction::_get_call_error(const String &p_where, const Variant **p_argptrs, const Variant &p_ret, const Callable::CallError &p_err) const {
+String GDScriptFunction::_get_call_error(const String &p_where, const Variant **p_argptrs, int p_argcount, const Variant &p_ret, const Callable::CallError &p_err) const {
 	switch (p_err.error) {
 	switch (p_err.error) {
 		case Callable::CallError::CALL_OK:
 		case Callable::CallError::CALL_OK:
 			return String();
 			return String();
@@ -160,7 +160,8 @@ String GDScriptFunction::_get_call_error(const String &p_where, const Variant **
 			}
 			}
 			return "Invalid call. Nonexistent " + p_where + ".";
 			return "Invalid call. Nonexistent " + p_where + ".";
 		case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
 		case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
-			ERR_FAIL_COND_V_MSG(p_err.argument < 0 || p_argptrs[p_err.argument] == nullptr, "Bug: Invalid CallError argument index or null pointer.", "Bug: Invalid CallError argument index or null pointer.");
+			ERR_FAIL_INDEX_V_MSG(p_err.argument, p_argcount, "Bug: Invalid call error argument index.", "Bug: Invalid call error argument index.");
+			ERR_FAIL_NULL_V_MSG(p_argptrs[p_err.argument], "Bug: Argument is null pointer.", "Bug: Argument is null pointer.");
 			// Handle the Object to Object case separately as we don't have further class details.
 			// Handle the Object to Object case separately as we don't have further class details.
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 			if (p_err.expected == Variant::OBJECT && p_argptrs[p_err.argument]->get_type() == p_err.expected) {
 			if (p_err.expected == Variant::OBJECT && p_argptrs[p_err.argument]->get_type() == p_err.expected) {
@@ -185,6 +186,27 @@ String GDScriptFunction::_get_call_error(const String &p_where, const Variant **
 	return "Bug: Invalid call error code " + itos(p_err.error) + ".";
 	return "Bug: Invalid call error code " + itos(p_err.error) + ".";
 }
 }
 
 
+String GDScriptFunction::_get_callable_call_error(const String &p_where, const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Variant &p_ret, const Callable::CallError &p_err) const {
+	Vector<Variant> binds;
+	p_callable.get_bound_arguments_ref(binds);
+
+	int args_unbound = p_callable.get_unbound_arguments_count();
+
+	if (p_argcount - args_unbound < 0) {
+		return "Callable unbinds " + itos(args_unbound) + " arguments, but called with " + itos(p_argcount);
+	} else {
+		Vector<const Variant *> argptrs;
+		argptrs.resize(p_argcount - args_unbound + binds.size());
+		for (int i = 0; i < p_argcount - args_unbound; i++) {
+			argptrs.write[i] = p_argptrs[i];
+		}
+		for (int i = 0; i < binds.size(); i++) {
+			argptrs.write[i + p_argcount - args_unbound] = &binds[i];
+		}
+		return _get_call_error(p_where, (const Variant **)argptrs.ptr(), argptrs.size(), p_ret, p_err);
+	}
+}
+
 void (*type_init_function_table[])(Variant *) = {
 void (*type_init_function_table[])(Variant *) = {
 	nullptr, // NIL (shouldn't be called).
 	nullptr, // NIL (shouldn't be called).
 	&VariantInitializer<bool>::init, // BOOL.
 	&VariantInitializer<bool>::init, // BOOL.
@@ -1703,7 +1725,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 
 
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 				if (err.error != Callable::CallError::CALL_OK) {
 				if (err.error != Callable::CallError::CALL_OK) {
-					err_text = _get_call_error("'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs, *dst, err);
+					err_text = _get_call_error("'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs, argc, *dst, err);
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
 #endif
 #endif
@@ -1957,7 +1979,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 							}
 							}
 						}
 						}
 					}
 					}
-					err_text = _get_call_error("function '" + methodstr + (is_callable ? "" : "' in base '" + basestr) + "'", (const Variant **)argptrs, temp_ret, err);
+
+					if (is_callable) {
+						err_text = _get_callable_call_error(vformat("function '%s'", methodstr), *base, (const Variant **)argptrs, argc, temp_ret, err);
+					} else {
+						err_text = _get_call_error(vformat("function '%s' in base '%s'", methodstr, basestr), (const Variant **)argptrs, argc, temp_ret, err);
+					}
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
 #endif // DEBUG_ENABLED
 #endif // DEBUG_ENABLED
@@ -2043,7 +2070,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 							}
 							}
 						}
 						}
 					}
 					}
-					err_text = _get_call_error("function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs, temp_ret, err);
+					err_text = _get_call_error("function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs, argc, temp_ret, err);
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
 #endif
 #endif
@@ -2076,7 +2103,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 
 
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 				if (err.error != Callable::CallError::CALL_OK) {
 				if (err.error != Callable::CallError::CALL_OK) {
-					err_text = _get_call_error("static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs, *ret, err);
+					err_text = _get_call_error("static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs, argc, *ret, err);
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
 #endif
 #endif
@@ -2120,7 +2147,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 #endif
 #endif
 
 
 				if (err.error != Callable::CallError::CALL_OK) {
 				if (err.error != Callable::CallError::CALL_OK) {
-					err_text = _get_call_error("static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs, *ret, err);
+					err_text = _get_call_error("static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs, argc, *ret, err);
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
 
 
@@ -2351,7 +2378,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 						// Call provided error string.
 						// Call provided error string.
 						err_text = vformat(R"*(Error calling utility function "%s()": %s)*", methodstr, *dst);
 						err_text = vformat(R"*(Error calling utility function "%s()": %s)*", methodstr, *dst);
 					} else {
 					} else {
-						err_text = _get_call_error(vformat(R"*(utility function "%s()")*", methodstr), (const Variant **)argptrs, *dst, err);
+						err_text = _get_call_error(vformat(R"*(utility function "%s()")*", methodstr), (const Variant **)argptrs, argc, *dst, err);
 					}
 					}
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
@@ -2408,7 +2435,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 						// Call provided error string.
 						// Call provided error string.
 						err_text = vformat(R"*(Error calling GDScript utility function "%s()": %s)*", methodstr, *dst);
 						err_text = vformat(R"*(Error calling GDScript utility function "%s()": %s)*", methodstr, *dst);
 					} else {
 					} else {
-						err_text = _get_call_error(vformat(R"*(GDScript utility function "%s()")*", methodstr), (const Variant **)argptrs, *dst, err);
+						err_text = _get_call_error(vformat(R"*(GDScript utility function "%s()")*", methodstr), (const Variant **)argptrs, argc, *dst, err);
 					}
 					}
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}
@@ -2475,7 +2502,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 
 
 				if (err.error != Callable::CallError::CALL_OK) {
 				if (err.error != Callable::CallError::CALL_OK) {
 					String methodstr = *methodname;
 					String methodstr = *methodname;
-					err_text = _get_call_error("function '" + methodstr + "'", (const Variant **)argptrs, *dst, err);
+					err_text = _get_call_error("function '" + methodstr + "'", (const Variant **)argptrs, argc, *dst, err);
 
 
 					OPCODE_BREAK;
 					OPCODE_BREAK;
 				}
 				}

+ 3 - 0
modules/gdscript/tests/scripts/runtime/errors/callable_call_invalid_arg_type.gd

@@ -0,0 +1,3 @@
+#debug-only
+func test():
+	print(load.bind([]).call())

+ 2 - 0
modules/gdscript/tests/scripts/runtime/errors/callable_call_invalid_arg_type.out

@@ -0,0 +1,2 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR at runtime/errors/callable_call_invalid_arg_type.gd:3 on test(): Invalid type in function '@GDScript::load (Callable)'. Cannot convert argument 1 from Array to String.

+ 2 - 2
modules/gdscript/tests/scripts/runtime/features/utility_func_as_callable.out

@@ -1,6 +1,6 @@
 GDTEST_OK
 GDTEST_OK
-@GlobalScope::print (Callable)
-@GDScript::len (Callable)
+@GlobalScope::print
+@GDScript::len
 1 2 3
 1 2 3
 1
 1
 3
 3