summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp33
-rw-r--r--modules/gdscript/gdscript.cpp4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp70
-rw-r--r--modules/gdscript/gdscript_compiler.cpp56
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gdscript/gdscript_vm.cpp20
-rw-r--r--modules/gdscript/gdscript_warning.cpp5
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd29
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out17
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/void_assignment.out5
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd9
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/typed_assignment.out12
-rw-r--r--modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp1
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp1
-rw-r--r--modules/gridmap/grid_map.cpp9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs9
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs10
-rw-r--r--modules/noise/noise_texture_2d.cpp1
-rw-r--r--modules/text_server_adv/text_server_adv.cpp10
-rw-r--r--modules/text_server_fb/text_server_fb.cpp10
47 files changed, 297 insertions, 114 deletions
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 0ebdbf090d..9457583d09 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -115,10 +115,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
if (from != line_length) {
- /* check if we are in entering a region */
+ // Check if we are in entering a region.
if (in_region == -1) {
for (int c = 0; c < color_regions.size(); c++) {
- /* check there is enough room */
+ // Check there is enough room.
int chars_left = line_length - from;
int start_key_length = color_regions[c].start_key.length();
int end_key_length = color_regions[c].end_key.length();
@@ -126,7 +126,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
continue;
}
- /* search the line */
+ // Search the line.
bool match = true;
const char32_t *start_key = color_regions[c].start_key.get_data();
for (int k = 0; k < start_key_length; k++) {
@@ -141,7 +141,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_region = c;
from += start_key_length;
- /* check if it's the whole line */
+ // Check if it's the whole line.
if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) {
if (from + end_key_length > line_length) {
// If it's key length and there is a '\', dont skip to highlight esc chars.
@@ -166,7 +166,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
}
- /* if we are in one find the end key */
+ // If we are in one, find the end key.
if (in_region != -1) {
Color region_color = color_regions[in_region].color;
if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) {
@@ -183,7 +183,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
highlighter_info["color"] = region_color;
color_map[j] = highlighter_info;
- /* search the line */
+ // Search the line.
int region_end_index = -1;
int end_key_length = color_regions[in_region].end_key.length();
const char32_t *end_key = color_regions[in_region].end_key.get_data();
@@ -267,14 +267,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_keyword = false;
}
- // allow ABCDEF in hex notation
+ // Allow ABCDEF in hex notation.
if (is_hex_notation && (is_hex_digit(str[j]) || is_a_digit)) {
is_a_digit = true;
} else {
is_hex_notation = false;
}
- // disallow anything not a 0 or 1 in binary notation
+ // Disallow anything not a 0 or 1 in binary notation.
if (is_bin_notation && !is_binary_digit(str[j])) {
is_a_digit = false;
is_bin_notation = false;
@@ -284,7 +284,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_number = true;
}
- // Special cases for numbers
+ // Special cases for numbers.
if (in_number && !is_a_digit) {
if (str[j] == 'b' && str[j - 1] == '0') {
is_bin_notation = true;
@@ -349,7 +349,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
if (col != Color()) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
- col = Color(); // keyword, member & global func indexing not allowed
+ col = Color(); // Keyword, member & global func indexing not allowed.
break;
} else if (str[k] > 32) {
break;
@@ -372,7 +372,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
k++;
}
- // check for space between name and bracket
+ // Check for space between name and bracket.
while (k < line_length && is_whitespace(str[k])) {
k++;
}
@@ -445,7 +445,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_member_variable = false;
}
- // Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand
+ // Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand.
if (!in_string_name && in_region == -1 && str[j] == '&' && !is_binary_op) {
if (j >= 2 && str[j - 1] == '&' && str[j - 2] != '&' && prev_is_binary_op) {
is_binary_op = true;
@@ -456,7 +456,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_string_name = false;
}
- // '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret
+ // '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret.
if (!in_node_path && in_region == -1 && str[j] == '^' && !is_binary_op && (j == 0 || (j > 0 && str[j - 1] != '^') || prev_is_binary_op)) {
in_node_path = true;
} else if (in_region != -1 || is_a_symbol) {
@@ -465,7 +465,8 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
if (!in_node_ref && in_region == -1 && (str[j] == '$' || (str[j] == '%' && !is_binary_op))) {
in_node_ref = true;
- } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) {
+ } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%') || (is_a_digit && j > 0 && (str[j - 1] == '$' || str[j - 1] == '/' || str[j - 1] == '%'))) {
+ // NodeRefs can't start with digits, so point out wrong syntax immediately.
in_node_ref = false;
}
@@ -525,7 +526,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
prev_type = current_type;
current_type = next_type;
- // no need to store regions...
+ // No need to store regions...
if (prev_type == REGION) {
prev_text = "";
prev_column = j;
@@ -533,7 +534,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
String text = str.substr(prev_column, j - prev_column).strip_edges();
prev_column = j;
- // ignore if just whitespace
+ // Ignore if just whitespace.
if (!text.is_empty()) {
prev_text = text;
}
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 1fe1561559..40bc2beb23 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -629,6 +629,10 @@ void GDScript::_update_doc() {
}
}
+ for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
+ E.value->_update_doc();
+ }
+
_add_doc(doc);
}
#endif
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index fc2e6e94f3..757e602ebe 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -937,6 +937,7 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
const GDScriptParser::EnumNode *prev_enum = current_enum;
current_enum = member.m_enum;
+ Dictionary dictionary;
for (int j = 0; j < member.m_enum->values.size(); j++) {
GDScriptParser::EnumNode::Value &element = member.m_enum->values.write[j];
@@ -960,11 +961,13 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
}
enum_type.enum_values[element.identifier->name] = element.value;
+ dictionary[String(element.identifier->name)] = element.value;
}
current_enum = prev_enum;
member.m_enum->set_datatype(enum_type);
+ member.m_enum->dictionary = dictionary;
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : member.m_enum->annotations) {
@@ -1748,12 +1751,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
type = p_variable->initializer->get_datatype();
-#ifdef DEBUG_ENABLED
- if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
- parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name);
- }
-#endif
-
if (p_variable->infer_datatype) {
type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
@@ -1843,12 +1840,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
}
type = p_constant->initializer->get_datatype();
-
-#ifdef DEBUG_ENABLED
- if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
- parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
- }
-#endif
}
if (p_constant->datatype_specifier != nullptr) {
@@ -2044,6 +2035,9 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
update_array_literal_element_type(expected_type, static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
}
}
+ if (has_expected_type && expected_type.is_hard_type() && expected_type.kind == GDScriptParser::DataType::BUILTIN && expected_type.builtin_type == Variant::NIL) {
+ push_error("A void function cannot return a value.", p_return);
+ }
result = p_return->return_value->get_datatype();
} else {
// Return type is null by default.
@@ -2259,30 +2253,26 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
p_assignment->set_datatype(op_type);
- if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {
+ if (assignee_type.is_hard_type() && !assignee_type.is_variant() && op_type.is_hard_type()) {
if (compatible) {
compatible = is_type_compatible(assignee_type, op_type, true, p_assignment->assigned_value);
if (!compatible) {
- if (assignee_type.is_hard_type()) {
- // Try reverse test since it can be a masked subtype.
- if (!is_type_compatible(op_type, assignee_type, true, p_assignment->assigned_value)) {
- push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value);
- } else {
- // TODO: Add warning.
- mark_node_unsafe(p_assignment);
- p_assignment->use_conversion_assign = true;
- }
+ // Try reverse test since it can be a masked subtype.
+ if (!is_type_compatible(op_type, assignee_type, true)) {
+ push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value);
} else {
- // TODO: Warning in this case.
+ // TODO: Add warning.
mark_node_unsafe(p_assignment);
+ p_assignment->use_conversion_assign = true;
}
}
} else {
push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", assignee_type.to_string(), assigned_value_type.to_string()), p_assignment);
}
- }
-
- if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {
+ } else if (assignee_type.is_hard_type() && !assignee_type.is_variant()) {
+ mark_node_unsafe(p_assignment);
+ p_assignment->use_conversion_assign = true;
+ } else {
mark_node_unsafe(p_assignment);
if (assignee_type.is_hard_type() && !assignee_type.is_variant()) {
p_assignment->use_conversion_assign = true;
@@ -2333,9 +2323,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
#ifdef DEBUG_ENABLED
- if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.is_hard_type() && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) {
- parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name);
- } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
+ if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION);
}
#endif
@@ -2650,6 +2638,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else if (GDScriptUtilityFunctions::function_exists(function_name)) {
MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
+ if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) {
+ push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call);
+ }
+
if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
// Can call on compilation.
Vector<const Variant *> args;
@@ -2693,6 +2685,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else if (Variant::has_utility_function(function_name)) {
MethodInfo function_info = info_from_utility_func(function_name);
+ if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) {
+ push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call);
+ }
+
if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
// Can call on compilation.
Vector<const Variant *> args;
@@ -2835,6 +2831,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
mark_lambda_use_self();
}
+ if (!p_is_root && return_type.is_hard_type() && return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) {
+ push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", p_call->function_name), p_call);
+ }
+
#ifdef DEBUG_ENABLED
if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
@@ -3140,10 +3140,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
break;
case GDScriptParser::ClassNode::Member::ENUM:
- if (p_base != nullptr && p_base->is_constant) {
- p_identifier->is_constant = true;
- p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
- }
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.m_enum->dictionary;
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
break;
case GDScriptParser::ClassNode::Member::VARIABLE:
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE;
@@ -3197,7 +3196,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
return;
case GDScriptParser::ClassNode::Member::ENUM:
p_identifier->set_datatype(member.get_datatype());
- p_identifier->is_constant = false;
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.m_enum->dictionary;
return;
case GDScriptParser::ClassNode::Member::CLASS:
p_identifier->set_datatype(member.get_datatype());
@@ -4174,7 +4174,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
r_default_arg_count++;
}
}
- r_return_type = found_function->get_datatype();
+ r_return_type = p_is_constructor ? p_base_type : found_function->get_datatype();
r_return_type.is_meta_type = false;
r_return_type.is_coroutine = found_function->is_coroutine;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index cf9e734b05..3c9387a837 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -538,20 +538,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Construct a built-in type.
Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- gen->write_construct(result, vtype, arguments);
+ gen->write_construct(return_addr, vtype, arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
// Variant utility function.
- gen->write_call_utility(result, call->function_name, arguments);
+ gen->write_call_utility(return_addr, call->function_name, arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
// GDScript utility function.
- gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
+ gen->write_call_gdscript_utility(return_addr, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
} else {
// Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
if (call->is_super) {
// Super call.
- gen->write_super_call(result, call->function_name, arguments);
+ gen->write_super_call(return_addr, call->function_name, arguments);
} else {
if (callee->type == GDScriptParser::Node::IDENTIFIER) {
// Self function call.
@@ -563,22 +563,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (_have_exact_arguments(method, arguments)) {
// Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, self, method, arguments);
+ gen->write_call_ptrcall(return_addr, self, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
- gen->write_call_method_bind(result, self, method, arguments);
+ gen->write_call_method_bind(return_addr, self, method, arguments);
}
} else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
GDScriptCodeGenerator::Address self;
self.mode = GDScriptCodeGenerator::Address::CLASS;
if (within_await) {
- gen->write_call_async(result, self, call->function_name, arguments);
+ gen->write_call_async(return_addr, self, call->function_name, arguments);
} else {
gen->write_call(return_addr, self, call->function_name, arguments);
}
} else {
if (within_await) {
- gen->write_call_self_async(result, call->function_name, arguments);
+ gen->write_call_self_async(return_addr, call->function_name, arguments);
} else {
gen->write_call_self(return_addr, call->function_name, arguments);
}
@@ -589,18 +589,18 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (subscript->is_attribute) {
// May be static built-in method call.
if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
- gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
+ gen->write_call_builtin_type_static(return_addr, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
} else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
// It's a static native method call.
- gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
+ gen->write_call_native_static(return_addr, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
} else {
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
if (within_await) {
- gen->write_call_async(result, base, call->function_name, arguments);
+ gen->write_call_async(return_addr, base, call->function_name, arguments);
} else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
// Native method, use faster path.
StringName class_name;
@@ -613,16 +613,16 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
MethodBind *method = ClassDB::get_method(class_name, call->function_name);
if (_have_exact_arguments(method, arguments)) {
// Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, base, method, arguments);
+ gen->write_call_ptrcall(return_addr, base, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
- gen->write_call_method_bind(result, base, method, arguments);
+ gen->write_call_method_bind(return_addr, base, method, arguments);
}
} else {
gen->write_call(return_addr, base, call->function_name, arguments);
}
} else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
- gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
+ gen->write_call_builtin_type(return_addr, base, base.type.builtin_type, call->function_name, arguments);
} else {
gen->write_call(return_addr, base, call->function_name, arguments);
}
@@ -2453,26 +2453,20 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
case GDScriptParser::ClassNode::Member::ENUM: {
const GDScriptParser::EnumNode *enum_n = member.m_enum;
+ StringName name = enum_n->identifier->name;
- // TODO: Make enums not be just a dictionary?
- Dictionary new_enum;
- for (int j = 0; j < enum_n->values.size(); j++) {
- // Needs to be string because Variant::get will convert to String.
- new_enum[String(enum_n->values[j].identifier->name)] = enum_n->values[j].value;
- }
-
- p_script->constants.insert(enum_n->identifier->name, new_enum);
+ p_script->constants.insert(name, enum_n->dictionary);
#ifdef TOOLS_ENABLED
- p_script->member_lines[enum_n->identifier->name] = enum_n->start_line;
- p_script->doc_enums[enum_n->identifier->name] = DocData::EnumDoc();
- p_script->doc_enums[enum_n->identifier->name].name = enum_n->identifier->name;
- p_script->doc_enums[enum_n->identifier->name].description = enum_n->doc_description;
+ p_script->member_lines[name] = enum_n->start_line;
+ p_script->doc_enums[name] = DocData::EnumDoc();
+ p_script->doc_enums[name].name = name;
+ p_script->doc_enums[name].description = enum_n->doc_description;
for (int j = 0; j < enum_n->values.size(); j++) {
DocData::ConstantDoc const_doc;
const_doc.name = enum_n->values[j].identifier->name;
const_doc.value = Variant(enum_n->values[j].value).operator String();
const_doc.description = enum_n->values[j].doc_description;
- p_script->doc_enums[enum_n->identifier->name].values.push_back(const_doc);
+ p_script->doc_enums[name].values.push_back(const_doc);
}
#endif
} break;
@@ -2642,10 +2636,6 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
}
}
-#ifdef TOOLS_ENABLED
- p_script->_update_doc();
-#endif
-
p_script->_init_rpc_methods_properties();
p_script->valid = true;
@@ -2730,6 +2720,10 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
return err;
}
+#ifdef TOOLS_ENABLED
+ p_script->_update_doc();
+#endif
+
return GDScriptCache::finish_compiling(main_script->get_path());
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 540ef1c561..fd2f7b3288 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -483,6 +483,7 @@ public:
IdentifierNode *identifier = nullptr;
Vector<Value> values;
+ Variant dictionary;
#ifdef TOOLS_ENABLED
String doc_description;
#endif // TOOLS_ENABLED
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index fdcc0625d7..bc8e33b01a 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -1533,8 +1533,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Callable::CallError err;
if (call_ret) {
GET_INSTRUCTION_ARG(ret, argc + 1);
+#ifdef DEBUG_ENABLED
+ Variant::Type base_type = base->get_type();
+ Object *base_obj = base->get_validated_object();
+ StringName base_class = base_obj ? base_obj->get_class_name() : StringName();
+#endif
base->callp(*methodname, (const Variant **)argptrs, argc, *ret, err);
#ifdef DEBUG_ENABLED
+ if (ret->get_type() == Variant::NIL) {
+ if (base_type == Variant::OBJECT) {
+ if (base_obj) {
+ MethodBind *method = ClassDB::get_method(base_class, *methodname);
+ if (*methodname == CoreStringNames::get_singleton()->_free || (method && !method->has_return())) {
+ err_text = R"(Trying to get a return value of a method that returns "void")";
+ OPCODE_BREAK;
+ }
+ }
+ } else if (Variant::has_builtin_method(base_type, *methodname) && !Variant::has_builtin_method_return_value(base_type, *methodname)) {
+ err_text = R"(Trying to get a return value of a method that returns "void")";
+ OPCODE_BREAK;
+ }
+ }
+
if (!call_async && ret->get_type() == Variant::OBJECT) {
// Check if getting a function state without await.
bool was_freed = false;
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 36bc051643..9ae4bdae56 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -80,10 +80,6 @@ String GDScriptWarning::get_message() const {
case STANDALONE_EXPRESSION: {
return "Standalone expression (the line has no effect).";
} break;
- case VOID_ASSIGNMENT: {
- CHECK_SYMBOLS(1);
- return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
- } break;
case NARROWING_CONVERSION: {
return "Narrowing conversion (float is converted to int and loses precision).";
} break;
@@ -202,7 +198,6 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"UNREACHABLE_CODE",
"UNREACHABLE_PATTERN",
"STANDALONE_EXPRESSION",
- "VOID_ASSIGNMENT",
"NARROWING_CONVERSION",
"INCOMPATIBLE_TERNARY",
"UNUSED_SIGNAL",
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 7e4e975510..df6ee71425 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -57,7 +57,6 @@ public:
UNREACHABLE_CODE, // Code after a return statement.
UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
STANDALONE_EXPRESSION, // Expression not assigned to a variable.
- VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable.
NARROWING_CONVERSION, // Float value into an integer slot, precision is lost.
INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible.
UNUSED_SIGNAL, // Signal is defined but never emitted.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd
new file mode 100644
index 0000000000..251be70088
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.gd
@@ -0,0 +1,10 @@
+class A:
+ func _init():
+ pass
+
+class B extends A: pass
+class C extends A: pass
+
+func test():
+ var x := B.new()
+ print(x is C)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out
new file mode 100644
index 0000000000..91d5125ec0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constructor_call_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "B" so it can't be of type "C".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd
new file mode 100644
index 0000000000..63587942f7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd
@@ -0,0 +1,2 @@
+func test() -> void:
+ return null
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out
new file mode 100644
index 0000000000..3c09f44ba9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+A void function cannot return a value.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd
new file mode 100644
index 0000000000..0ee4e7ea36
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd
@@ -0,0 +1,4 @@
+func test() -> void:
+ var a
+ a = 1
+ return a
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out
new file mode 100644
index 0000000000..3c09f44ba9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+A void function cannot return a value.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd
new file mode 100644
index 0000000000..a3450966cc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd
@@ -0,0 +1,3 @@
+func test():
+ var builtin := []
+ print(builtin.reverse()) # Built-in type method.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out
new file mode 100644
index 0000000000..225c85e9c7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "reverse()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd
new file mode 100644
index 0000000000..2162a181ac
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd
@@ -0,0 +1,5 @@
+func foo() -> void:
+ pass
+
+func test():
+ print(foo()) # Custom method.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out
new file mode 100644
index 0000000000..2b1a607883
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "foo()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd
new file mode 100644
index 0000000000..f3443d985e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd
@@ -0,0 +1,2 @@
+func test():
+ print(print_debug()) # GDScript utility function.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out
new file mode 100644
index 0000000000..502c18ab9d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "print_debug()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd
new file mode 100644
index 0000000000..b8e81b160a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd
@@ -0,0 +1,3 @@
+func test():
+ var obj := Node.new()
+ print(obj.free()) # Native type method.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out
new file mode 100644
index 0000000000..88be39345b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "free()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd
new file mode 100644
index 0000000000..8eabed4271
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd
@@ -0,0 +1,2 @@
+func test():
+ print(print()) # Built-in utility function.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out
new file mode 100644
index 0000000000..ebf43186be
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "print()" because it returns "void".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd
new file mode 100644
index 0000000000..2ce588373b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.gd
@@ -0,0 +1,29 @@
+class Outer:
+ enum OuterEnum { OuterValue = 3 }
+ const OuterConst := OuterEnum
+
+ class Inner:
+ enum InnerEnum { InnerValue = 7 }
+ const InnerConst := InnerEnum
+
+ static func test() -> void:
+ print(OuterEnum.size());
+ print(OuterEnum.OuterValue);
+ print(OuterConst.size());
+ print(OuterConst.OuterValue);
+ print(Outer.OuterEnum.size());
+ print(Outer.OuterEnum.OuterValue);
+ print(Outer.OuterConst.size());
+ print(Outer.OuterConst.OuterValue);
+
+ print(InnerEnum.size());
+ print(InnerEnum.InnerValue);
+ print(InnerConst.size());
+ print(InnerConst.InnerValue);
+ print(Inner.InnerEnum.size());
+ print(Inner.InnerEnum.InnerValue);
+ print(Inner.InnerConst.size());
+ print(Inner.InnerConst.InnerValue);
+
+func test():
+ Outer.Inner.test()
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out
new file mode 100644
index 0000000000..e049f85b6e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_as_const.out
@@ -0,0 +1,17 @@
+GDTEST_OK
+1
+3
+1
+3
+1
+3
+1
+3
+1
+7
+1
+7
+1
+7
+1
+7
diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd
new file mode 100644
index 0000000000..c9caef7d7c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd
@@ -0,0 +1,5 @@
+func variant() -> Variant:
+ return 'variant'
+
+func test():
+ print(variant())
diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out
new file mode 100644
index 0000000000..57fe608cc5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+variant
diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd
deleted file mode 100644
index b4a42b3e3d..0000000000
--- a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd
+++ /dev/null
@@ -1,6 +0,0 @@
-func i_return_void() -> void:
- return
-
-
-func test():
- var __ = i_return_void()
diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out
deleted file mode 100644
index 84c9598f9a..0000000000
--- a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out
+++ /dev/null
@@ -1,5 +0,0 @@
-GDTEST_OK
->> WARNING
->> Line: 6
->> VOID_ASSIGNMENT
->> Assignment operation, but the function 'i_return_void()' returns void.
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd
new file mode 100644
index 0000000000..a3daf70627
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.gd
@@ -0,0 +1,4 @@
+func test():
+ var obj
+ obj = Node.new()
+ print(obj.free())
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out
new file mode 100644
index 0000000000..5edaf19442
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_free_call.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/use_return_value_of_free_call.gd
+>> 4
+>> Trying to get a return value of a method that returns "void"
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd
new file mode 100644
index 0000000000..49fb76ad1f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.gd
@@ -0,0 +1,4 @@
+func test():
+ var value
+ value = []
+ print(value.reverse())
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out
new file mode 100644
index 0000000000..128356ff8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_builtin_method_call.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/use_return_value_of_void_builtin_method_call.gd
+>> 4
+>> Trying to get a return value of a method that returns "void"
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd
new file mode 100644
index 0000000000..44f9aa467a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.gd
@@ -0,0 +1,4 @@
+func test():
+ var obj
+ obj = RefCounted.new()
+ print(obj.notify_property_list_changed())
diff --git a/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out
new file mode 100644
index 0000000000..e02c206778
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/use_return_value_of_void_native_method_call.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/use_return_value_of_void_native_method_call.gd
+>> 4
+>> Trying to get a return value of a method that returns "void"
diff --git a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
index 5303fb04e2..9b64084fa6 100644
--- a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd
@@ -15,10 +15,10 @@ func test():
var string_array: Array[String] = []
var stringname_array: Array[StringName] = []
- assert(!string_array.push_back(&"abc"))
+ string_array.push_back(&"abc")
print("Array[String] insert converted: ", typeof(string_array[0]) == TYPE_STRING)
- assert(!stringname_array.push_back("abc"))
+ stringname_array.push_back("abc")
print("Array[StringName] insert converted: ", typeof(stringname_array[0]) == TYPE_STRING_NAME)
print("StringName in Array[String]: ", &"abc" in string_array)
@@ -28,8 +28,8 @@ func test():
assert(!packed_string_array.push_back("abc"))
print("StringName in PackedStringArray: ", &"abc" in packed_string_array)
- assert(!string_array.push_back("abc"))
+ string_array.push_back("abc")
print("StringName finds String in Array: ", string_array.find(&"abc"))
- assert(!stringname_array.push_back(&"abc"))
+ stringname_array.push_back(&"abc")
print("String finds StringName in Array: ", stringname_array.find("abc"))
diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd
new file mode 100644
index 0000000000..22e54cf91c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.gd
@@ -0,0 +1,9 @@
+func test():
+ var x: int = 2
+ var y = 3.14
+ var z := 2.72
+ print(typeof(x))
+ x = y
+ print(typeof(x))
+ x = z
+ print(typeof(x))
diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_assignment.out b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.out
new file mode 100644
index 0000000000..4a268dd8e0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/typed_assignment.out
@@ -0,0 +1,12 @@
+GDTEST_OK
+>> WARNING
+>> Line: 6
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+>> WARNING
+>> Line: 8
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+2
+2
+2
diff --git a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
index cfa498af65..4b71511582 100644
--- a/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
+++ b/modules/gltf/extensions/gltf_document_extension_convert_importer_mesh.cpp
@@ -59,6 +59,7 @@ Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_sta
mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
node->replace_by(mesh_instance_node_3d);
delete_queue.push_back(node);
+ node = mesh_instance_node_3d;
} else {
memdelete(mesh_instance_node_3d);
}
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 89ef9ddd90..186e6a504f 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -1405,6 +1405,7 @@ GridMapEditor::GridMapEditor() {
}
GridMapEditor::~GridMapEditor() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
_clear_clipboard_data();
for (int i = 0; i < 3; i++) {
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index e396d77d86..d23d68ffba 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -796,6 +796,10 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
}
void GridMap::_octant_exit_world(const OctantKey &p_key) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
+
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
@@ -834,6 +838,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
}
void GridMap::_octant_clean_up(const OctantKey &p_key) {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
+ ERR_FAIL_NULL(NavigationServer3D::get_singleton());
+
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
@@ -1186,6 +1194,7 @@ Vector3 GridMap::_get_offset() const {
}
void GridMap::clear_baked_meshes() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
for (int i = 0; i < baked_meshes.size(); i++) {
RS::get_singleton()->free(baked_meshes[i].instance);
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index fb32f6192f..eae7e41da8 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -45,8 +45,11 @@ namespace Godot.SourceGenerators
return false;
})
)
- // Ignore classes whose name is not the same as the file name
- .Where(x => Path.GetFileNameWithoutExtension(x.cds.SyntaxTree.FilePath) == x.symbol.Name)
+ .Where(x =>
+ // Ignore classes whose name is not the same as the file name
+ Path.GetFileNameWithoutExtension(x.cds.SyntaxTree.FilePath) == x.symbol.Name &&
+ // Ignore generic classes
+ !x.symbol.IsGenericType)
.GroupBy(x => x.symbol)
.ToDictionary(g => g.Key, g => g.Select(x => x.cds));
@@ -150,8 +153,6 @@ namespace Godot.SourceGenerators
first = false;
sourceBuilder.Append("typeof(");
sourceBuilder.Append(qualifiedName);
- if (godotClass.Key.IsGenericType)
- sourceBuilder.Append($"<{new string(',', godotClass.Key.TypeParameters.Count() - 1)}>");
sourceBuilder.Append(")");
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index e6a8054ae2..dafa83431b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -297,7 +297,7 @@ namespace Godot.Bridge
foreach (var type in assembly.GetTypes())
{
- if (type.IsNested)
+ if (type.IsNested || type.IsGenericType)
continue;
if (!typeOfGodotObject.IsAssignableFrom(type))
@@ -314,9 +314,12 @@ namespace Godot.Bridge
if (scriptTypes != null)
{
- for (int i = 0; i < scriptTypes.Length; i++)
+ foreach (var type in scriptTypes)
{
- LookupScriptForClass(scriptTypes[i]);
+ if (type.IsGenericType)
+ continue;
+
+ LookupScriptForClass(type);
}
}
}
@@ -729,6 +732,7 @@ namespace Godot.Bridge
{
ExceptionUtils.LogException(e);
*outTool = godot_bool.False;
+ *outMethodsDest = NativeFuncs.godotsharp_array_new();
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
*outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new();
*outBaseScript = default;
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index 8c785d7591..1b6f1d7897 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -40,6 +40,7 @@ NoiseTexture2D::NoiseTexture2D() {
}
NoiseTexture2D::~NoiseTexture2D() {
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index f3e7ae9b83..1c744afec0 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -385,11 +385,17 @@ void TextServerAdvanced::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontAdvanced *fd = font_owner.get_or_null(p_rid);
- font_owner.free(p_rid);
+ {
+ MutexLock lock(fd->mutex);
+ font_owner.free(p_rid);
+ }
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);
- shaped_owner.free(p_rid);
+ {
+ MutexLock lock(sd->mutex);
+ shaped_owner.free(p_rid);
+ }
memdelete(sd);
}
}
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index ea7b7a271b..9fd8c8fb37 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -115,11 +115,17 @@ void TextServerFallback::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontFallback *fd = font_owner.get_or_null(p_rid);
- font_owner.free(p_rid);
+ {
+ MutexLock lock(fd->mutex);
+ font_owner.free(p_rid);
+ }
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_rid);
- shaped_owner.free(p_rid);
+ {
+ MutexLock lock(sd->mutex);
+ shaped_owner.free(p_rid);
+ }
memdelete(sd);
}
}