diff options
Diffstat (limited to 'modules/gdscript')
38 files changed, 240 insertions, 87 deletions
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 |