diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp index 8357887ba1..8340d124c0 100644 --- a/modules/gdscript/editor/gdscript_docgen.cpp +++ b/modules/gdscript/editor/gdscript_docgen.cpp @@ -443,9 +443,6 @@ void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_ method_doc.return_type = "void"; } else if (!m_func->get_datatype().is_variant()) { _doctype_from_gdtype(m_func->get_datatype(), method_doc.return_type, method_doc.return_enum, true); - } else if (!m_func->body->has_return) { - // If no `return` statement, then return type is `void`, not `Variant`. - method_doc.return_type = "void"; } else { method_doc.return_type = "Variant"; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index f3e7cc8d02..563d1acc5c 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2510,15 +2510,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ } if (p_func) { - // If no `return` statement, then return type is `void`, not `Variant`. - if (p_func->body->has_return) { - gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); - method_info.return_val = p_func->get_datatype().to_property_info(String()); - } else { - gd_function->return_type = GDScriptDataType(); - gd_function->return_type.kind = GDScriptDataType::BUILTIN; - gd_function->return_type.builtin_type = Variant::NIL; - } + gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); + method_info.return_val = p_func->get_datatype().to_property_info(String()); if (p_func->is_vararg()) { gd_function->_vararg_index = vararg_addr.address; diff --git a/modules/gdscript/tests/scripts/analyzer/errors/untyped_override_untyped_return.gd b/modules/gdscript/tests/scripts/analyzer/errors/untyped_override_untyped_return.gd new file mode 100644 index 0000000000..ac16e56a5f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/untyped_override_untyped_return.gd @@ -0,0 +1,118 @@ +@abstract class A: + @abstract func abstract_untyped_1() + @abstract func abstract_untyped_2() + @abstract func abstract_untyped_3() + @abstract func abstract_untyped_4() + + @abstract func abstract_void_1() -> void + @abstract func abstract_void_2() -> void + @abstract func abstract_void_3() -> void + @abstract func abstract_void_4() -> void + + @abstract func abstract_variant_1() -> Variant + @abstract func abstract_variant_2() -> Variant + @abstract func abstract_variant_3() -> Variant + @abstract func abstract_variant_4() -> Variant + + @abstract func abstract_int_1() -> int + @abstract func abstract_int_2() -> int + @abstract func abstract_int_3() -> int + @abstract func abstract_int_4() -> int + + func concrete_untyped_pass_1(): pass + func concrete_untyped_pass_2(): pass + func concrete_untyped_pass_3(): pass + func concrete_untyped_pass_4(): pass + + func concrete_untyped_return_empty_1(): return + func concrete_untyped_return_empty_2(): return + func concrete_untyped_return_empty_3(): return + func concrete_untyped_return_empty_4(): return + + func concrete_untyped_return_null_1(): return null + func concrete_untyped_return_null_2(): return null + func concrete_untyped_return_null_3(): return null + func concrete_untyped_return_null_4(): return null + + func concrete_untyped_return_int_1(): return 0 + func concrete_untyped_return_int_2(): return 0 + func concrete_untyped_return_int_3(): return 0 + func concrete_untyped_return_int_4(): return 0 + + func concrete_void_1() -> void: pass + func concrete_void_2() -> void: pass + func concrete_void_3() -> void: pass + func concrete_void_4() -> void: pass + + func concrete_variant_1() -> Variant: return null + func concrete_variant_2() -> Variant: return null + func concrete_variant_3() -> Variant: return null + func concrete_variant_4() -> Variant: return null + + func concrete_int_1() -> int: return 0 + func concrete_int_2() -> int: return 0 + func concrete_int_3() -> int: return 0 + func concrete_int_4() -> int: return 0 + +class B extends A: + func abstract_untyped_1(): pass + func abstract_untyped_2(): return + func abstract_untyped_3(): return null + func abstract_untyped_4(): return 0 + + func abstract_void_1(): pass + func abstract_void_2(): return + func abstract_void_3(): return null # Error. + func abstract_void_4(): return 0 # Error. + + func abstract_variant_1(): pass # Error. + func abstract_variant_2(): return # TODO: Treated as `return null`, but should produce an empty return error. + func abstract_variant_3(): return null + func abstract_variant_4(): return 0 + + func abstract_int_1(): pass # Error. + func abstract_int_2(): return # Error. # TODO: Treated as `return null`. It would be nice to clarify the error. + func abstract_int_3(): return null # Error. + func abstract_int_4(): return 0 + + # `concrete_untyped_*()` overrides should not produce errors. + + func concrete_untyped_pass_1(): pass + func concrete_untyped_pass_2(): return + func concrete_untyped_pass_3(): return null + func concrete_untyped_pass_4(): return 0 + + func concrete_untyped_return_empty_1(): pass + func concrete_untyped_return_empty_2(): return + func concrete_untyped_return_empty_3(): return null + func concrete_untyped_return_empty_4(): return 0 + + func concrete_untyped_return_null_1(): pass + func concrete_untyped_return_null_2(): return + func concrete_untyped_return_null_3(): return null + func concrete_untyped_return_null_4(): return 0 + + func concrete_untyped_return_int_1(): pass + func concrete_untyped_return_int_2(): return + func concrete_untyped_return_int_3(): return null + func concrete_untyped_return_int_4(): return 0 + + # Same as for abstract methods. + + func concrete_void_1(): pass + func concrete_void_2(): return + func concrete_void_3(): return null # Error. + func concrete_void_4(): return 0 # Error. + + func concrete_variant_1(): pass # Error. + func concrete_variant_2(): return # TODO: Treated as `return null`, but should produce an empty return error. + func concrete_variant_3(): return null + func concrete_variant_4(): return 0 + + func concrete_int_1(): pass # Error. + func concrete_int_2(): return # Error. # TODO: Treated as `return null`. It would be nice to clarify the error. + func concrete_int_3(): return null # Error. + func concrete_int_4(): return 0 + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/untyped_override_untyped_return.out b/modules/gdscript/tests/scripts/analyzer/errors/untyped_override_untyped_return.out new file mode 100644 index 0000000000..8b785e016a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/untyped_override_untyped_return.out @@ -0,0 +1,15 @@ +GDTEST_ANALYZER_ERROR +>> ERROR at line 65: A void function cannot return a value. +>> ERROR at line 66: A void function cannot return a value. +>> ERROR at line 68: Not all code paths return a value. +>> ERROR at line 73: Not all code paths return a value. +>> ERROR at line 74: Cannot return value of type "null" because the function return type is "int". +>> ERROR at line 75: Cannot return a value of type "null" as "int". +>> ERROR at line 75: Cannot return value of type "null" because the function return type is "int". +>> ERROR at line 104: A void function cannot return a value. +>> ERROR at line 105: A void function cannot return a value. +>> ERROR at line 107: Not all code paths return a value. +>> ERROR at line 112: Not all code paths return a value. +>> ERROR at line 113: Cannot return value of type "null" because the function return type is "int". +>> ERROR at line 114: Cannot return a value of type "null" as "int". +>> ERROR at line 114: Cannot return value of type "null" because the function return type is "int". diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd index 54a39c0860..8ab3b1f908 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.gd +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd @@ -51,8 +51,8 @@ var test_var_hard_dictionary_my_class: Dictionary[MyClass, MyClass] static func test_static_func(): pass -func test_func_implicit_void(): pass -func test_func_explicit_void() -> void: pass +func test_func_untyped(): pass +func test_func_void() -> void: pass func test_func_weak_null(): return null func test_func_weak_int(): return 1 func test_func_hard_variant() -> Variant: return null diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.out b/modules/gdscript/tests/scripts/runtime/features/member_info.out index 0257bb581f..952ffc85c6 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.out +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.out @@ -38,15 +38,15 @@ var test_var_hard_dictionary_my_enum: Dictionary[TestMemberInfo.MyEnum, TestMemb var test_var_hard_dictionary_resource: Dictionary[Resource, Resource] var test_var_hard_dictionary_this: Dictionary[TestMemberInfo, TestMemberInfo] var test_var_hard_dictionary_my_class: Dictionary[RefCounted, RefCounted] -static func test_static_func() -> void -func test_func_implicit_void() -> void -func test_func_explicit_void() -> void +static func test_static_func() -> Variant +func test_func_untyped() -> Variant +func test_func_void() -> void func test_func_weak_null() -> Variant func test_func_weak_int() -> Variant func test_func_hard_variant() -> Variant func test_func_hard_int() -> int -func test_func_args_1(_a: int, _b: Array[int], _c: Dictionary[int, int], _d: int = 1, _e: Variant = 2) -> void -func test_func_args_2(_a: Variant = 1, _b: Variant = null, _c: Variant = null, _d: Variant = 3) -> void +func test_func_args_1(_a: int, _b: Array[int], _c: Dictionary[int, int], _d: int = 1, _e: Variant = 2) -> Variant +func test_func_args_2(_a: Variant = 1, _b: Variant = null, _c: Variant = null, _d: Variant = 3) -> Variant signal test_signal_1() signal test_signal_2(a: Variant, b: Variant) signal test_signal_3(a: int, b: Array[int], c: Dictionary[int, int]) diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_abstract_methods.gd b/modules/gdscript/tests/scripts/runtime/features/member_info_abstract_methods.gd new file mode 100644 index 0000000000..533a4c4888 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/member_info_abstract_methods.gd @@ -0,0 +1,38 @@ +@abstract class A: + @abstract func test_untyped_1() + @abstract func test_untyped_2() + @abstract func test_untyped_3() + @abstract func test_untyped_4() + @abstract func test_void() -> void + @abstract func test_variant() -> Variant + @abstract func test_int() -> int + +class B extends A: + func test_untyped_1(): pass + func test_untyped_2(): return + func test_untyped_3(): return null + func test_untyped_4(): return 0 + func test_void() -> void: pass + func test_variant() -> Variant: return null + func test_int() -> int: return 0 + +func test_script_method_signature(name: String, script: Script) -> void: + prints("---", name, "---") + for method: Dictionary in script.get_script_method_list(): + if str(method.name).begins_with("test_"): + print(Utils.get_method_signature(method)) + +func test_instance_method_signature(name: String, instance: Object) -> void: + prints("---", name, "---") + for method in instance.get_method_list(): + if str(method.name).begins_with("test_"): + print(Utils.get_method_signature(method)) + +func test(): + var b := B.new() + + print("=== Script Methods ===") + test_script_method_signature("A", A as GDScript) + test_script_method_signature("B", B as GDScript) + print("=== Instance Methods ===") + test_instance_method_signature("B", b) diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_abstract_methods.out b/modules/gdscript/tests/scripts/runtime/features/member_info_abstract_methods.out new file mode 100644 index 0000000000..fe23fd3c64 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/member_info_abstract_methods.out @@ -0,0 +1,41 @@ +GDTEST_OK +=== Script Methods === +--- A --- +@abstract func test_untyped_1() -> Variant +@abstract func test_untyped_2() -> Variant +@abstract func test_untyped_3() -> Variant +@abstract func test_untyped_4() -> Variant +@abstract func test_void() -> void +@abstract func test_variant() -> Variant +@abstract func test_int() -> int +--- B --- +func test_untyped_1() -> Variant +func test_untyped_2() -> Variant +func test_untyped_3() -> Variant +func test_untyped_4() -> Variant +func test_void() -> void +func test_variant() -> Variant +func test_int() -> int +@abstract func test_untyped_1() -> Variant +@abstract func test_untyped_2() -> Variant +@abstract func test_untyped_3() -> Variant +@abstract func test_untyped_4() -> Variant +@abstract func test_void() -> void +@abstract func test_variant() -> Variant +@abstract func test_int() -> int +=== Instance Methods === +--- B --- +func test_untyped_1() -> Variant +func test_untyped_2() -> Variant +func test_untyped_3() -> Variant +func test_untyped_4() -> Variant +func test_void() -> void +func test_variant() -> Variant +func test_int() -> int +@abstract func test_untyped_1() -> Variant +@abstract func test_untyped_2() -> Variant +@abstract func test_untyped_3() -> Variant +@abstract func test_untyped_4() -> Variant +@abstract func test_void() -> void +@abstract func test_variant() -> Variant +@abstract func test_int() -> int diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out index 663e74568c..d914186ce5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out +++ b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out @@ -24,39 +24,39 @@ var test_var_b2: Variant --- C --- === Member Methods === --- B --- -static func test_static_func_b1() -> void -static func test_static_func_b2() -> void -func test_abstract_func_1() -> void -func test_abstract_func_2() -> void -func test_override_func_1() -> void -func test_override_func_2() -> void -func test_func_b1() -> void -func test_func_b2() -> void -@abstract func test_abstract_func_1() -> void -@abstract func test_abstract_func_2() -> void -func test_override_func_1() -> void -func test_override_func_2() -> void +static func test_static_func_b1() -> Variant +static func test_static_func_b2() -> Variant +func test_abstract_func_1() -> Variant +func test_abstract_func_2() -> Variant +func test_override_func_1() -> Variant +func test_override_func_2() -> Variant +func test_func_b1() -> Variant +func test_func_b2() -> Variant +@abstract func test_abstract_func_1() -> Variant +@abstract func test_abstract_func_2() -> Variant +func test_override_func_1() -> Variant +func test_override_func_2() -> Variant --- C --- -static func test_static_func_c1() -> void -static func test_static_func_c2() -> void -func test_abstract_func_1() -> void -func test_abstract_func_2() -> void -func test_override_func_1() -> void -func test_override_func_2() -> void -func test_func_c1() -> void -func test_func_c2() -> void -static func test_static_func_b1() -> void -static func test_static_func_b2() -> void -func test_abstract_func_1() -> void -func test_abstract_func_2() -> void -func test_override_func_1() -> void -func test_override_func_2() -> void -func test_func_b1() -> void -func test_func_b2() -> void -@abstract func test_abstract_func_1() -> void -@abstract func test_abstract_func_2() -> void -func test_override_func_1() -> void -func test_override_func_2() -> void +static func test_static_func_c1() -> Variant +static func test_static_func_c2() -> Variant +func test_abstract_func_1() -> Variant +func test_abstract_func_2() -> Variant +func test_override_func_1() -> Variant +func test_override_func_2() -> Variant +func test_func_c1() -> Variant +func test_func_c2() -> Variant +static func test_static_func_b1() -> Variant +static func test_static_func_b2() -> Variant +func test_abstract_func_1() -> Variant +func test_abstract_func_2() -> Variant +func test_override_func_1() -> Variant +func test_override_func_2() -> Variant +func test_func_b1() -> Variant +func test_func_b2() -> Variant +@abstract func test_abstract_func_1() -> Variant +@abstract func test_abstract_func_2() -> Variant +func test_override_func_1() -> Variant +func test_override_func_2() -> Variant === Signals === --- B --- signal test_signal_b1()