diff options
Diffstat (limited to 'modules')
5 files changed, 57 insertions, 13 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index e058187860..38d5ae6b77 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2618,7 +2618,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o result = get_operation_type(p_binary_op->variant_op, left_type, right_type, valid, p_binary_op); if (!valid) { push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", left_type.to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); - } else if (result.type_source != GDScriptParser::DataType::ANNOTATED_EXPLICIT) { + } else if (!result.is_hard_type()) { mark_node_unsafe(p_binary_op); } } else { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 60b8c8f880..9e1dca16ac 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2018,6 +2018,32 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ bool is_initializer = p_func && !p_for_lambda && p_func->identifier->name == GDScriptLanguage::get_singleton()->strings._init; bool is_implicit_ready = !p_func && p_for_ready; + if (!p_for_lambda && is_implicit_initializer) { + // Initialize the default values for type variables before anything. + // This avoids crashes if they are accessed with validated calls before being properly initialized. + // It may happen with out-of-order access or with `@onready` variables. + for (const GDScriptParser::ClassNode::Member &member : p_class->members) { + if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) { + continue; + } + + const GDScriptParser::VariableNode *field = member.variable; + GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script); + GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type); + + if (field_type.has_type) { + codegen.generator->write_newline(field->start_line); + + if (field_type.has_container_element_type()) { + codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); + } else if (field_type.kind == GDScriptDataType::BUILTIN) { + codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); + } + // The `else` branch is for objects, in such case we leave it as `null`. + } + } + } + if (!p_for_lambda && (is_implicit_initializer || is_implicit_ready)) { // Initialize class fields. for (int i = 0; i < p_class->members.size(); i++) { @@ -2051,16 +2077,6 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } - } else if (field_type.has_type) { - codegen.generator->write_newline(field->start_line); - - // Initialize with default for type. - if (field_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); - } else if (field_type.kind == GDScriptDataType::BUILTIN) { - codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>()); - } - // The `else` branch is for objects, in such case we leave it as `null`. } } } diff --git a/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.gd b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.gd new file mode 100644 index 0000000000..03278e453f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.gd @@ -0,0 +1,20 @@ +extends Node + +@onready var later_inferred := [1] +@onready var later_static : Array +@onready var later_static_with_init : Array = [1] +@onready var later_untyped = [1] + +func test(): + assert(typeof(later_inferred) == TYPE_ARRAY) + assert(later_inferred.size() == 0) + + assert(typeof(later_static) == TYPE_ARRAY) + assert(later_static.size() == 0) + + assert(typeof(later_static_with_init) == TYPE_ARRAY) + assert(later_static_with_init.size() == 0) + + assert(typeof(later_untyped) == TYPE_NIL) + + print("ok") diff --git a/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.out b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/default_set_beforehand.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index b38f7225a2..6c961813b4 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -251,8 +251,12 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { /* we're expecting more header packets. */ while ((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3)) { + int ret = 0; + /* look for further theora headers */ - int ret = ogg_stream_packetout(&to, &op); + if (theora_p && theora_p < 3) { + ret = ogg_stream_packetout(&to, &op); + } while (theora_p && theora_p < 3 && ret) { if (ret < 0) { fprintf(stderr, "Error parsing Theora stream headers; corrupt stream?\n"); @@ -269,7 +273,9 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { } /* look for more vorbis header packets */ - ret = ogg_stream_packetout(&vo, &op); + if (vorbis_p && vorbis_p < 3) { + ret = ogg_stream_packetout(&vo, &op); + } while (vorbis_p && vorbis_p < 3 && ret) { if (ret < 0) { fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n"); |