diff options
-rw-r--r-- | editor/plugins/text_shader_editor.cpp | 5 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 68 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd | 32 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/analyzer/features/hard_variants.out | 5 | ||||
-rw-r--r-- | modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs | 20 | ||||
-rw-r--r-- | modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs | 15 | ||||
-rw-r--r-- | modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs | 15 | ||||
-rw-r--r-- | scene/resources/shader.cpp | 13 | ||||
-rw-r--r-- | scene/resources/shader.h | 2 | ||||
-rw-r--r-- | scene/resources/shader_include.cpp | 12 | ||||
-rw-r--r-- | scene/resources/shader_include.h | 3 | ||||
-rw-r--r-- | servers/rendering/shader_preprocessor.cpp | 5 |
12 files changed, 122 insertions, 73 deletions
diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 1b29999796..ffd9564816 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -383,11 +383,12 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa List<ScriptLanguage::CodeCompletionOption> pp_defines; ShaderPreprocessor preprocessor; String code; - complete_from_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path()).get_base_dir(); + String resource_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path()); + complete_from_path = resource_path.get_base_dir(); if (!complete_from_path.ends_with("/")) { complete_from_path += "/"; } - preprocessor.preprocess(p_code, "", code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths); + preprocessor.preprocess(p_code, resource_path, code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths); complete_from_path = String(); if (pp_options.size()) { for (const ScriptLanguage::CodeCompletionOption &E : pp_options) { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index f6385dd132..8c3521c530 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1999,7 +1999,7 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { #ifdef DEBUG_ENABLED } else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) { parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION); - } else if (result.is_variant()) { + } else if (result.is_variant() && !expected_type.is_variant()) { mark_node_unsafe(p_return); #endif } @@ -2375,43 +2375,41 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o GDScriptParser::DataType result; - if (left_type.is_variant() || right_type.is_variant()) { - // Cannot infer type because one operand can be anything. - result.kind = GDScriptParser::DataType::VARIANT; - mark_node_unsafe(p_binary_op); - } else { - if (p_binary_op->variant_op < Variant::OP_MAX) { - bool valid = false; - 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 (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { - GDScriptParser::DataType test_type = right_type; - test_type.is_meta_type = false; - - if (!is_type_compatible(test_type, left_type, false)) { - // Test reverse as well to consider for subtypes. - if (!is_type_compatible(left_type, test_type, false)) { - if (left_type.is_hard_type()) { - push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", left_type.to_string(), test_type.to_string()), p_binary_op->left_operand); - } else { - // TODO: Warning. - mark_node_unsafe(p_binary_op); - } - } - } + if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { + GDScriptParser::DataType test_type = right_type; + test_type.is_meta_type = false; - // "is" operator is always a boolean anyway. - result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - result.kind = GDScriptParser::DataType::BUILTIN; - result.builtin_type = Variant::BOOL; + if (!is_type_compatible(test_type, left_type, false) && !is_type_compatible(left_type, test_type, false)) { + if (left_type.is_hard_type()) { + push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", left_type.to_string(), test_type.to_string()), p_binary_op->left_operand); } else { - ERR_PRINT("Parser bug: unknown binary operation."); + // TODO: Warning. + mark_node_unsafe(p_binary_op); } } + + // "is" operator is always a boolean anyway. + result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + result.kind = GDScriptParser::DataType::BUILTIN; + result.builtin_type = Variant::BOOL; + } else if ((p_binary_op->variant_op == Variant::OP_EQUAL || p_binary_op->variant_op == Variant::OP_NOT_EQUAL) && + ((left_type.kind == GDScriptParser::DataType::BUILTIN && left_type.builtin_type == Variant::NIL) || (right_type.kind == GDScriptParser::DataType::BUILTIN && right_type.builtin_type == Variant::NIL))) { + // "==" and "!=" operators always return a boolean when comparing to null. + result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + result.kind = GDScriptParser::DataType::BUILTIN; + result.builtin_type = Variant::BOOL; + } else if (left_type.is_variant() || right_type.is_variant()) { + // Cannot infer type because one operand can be anything. + result.kind = GDScriptParser::DataType::VARIANT; + mark_node_unsafe(p_binary_op); + } else if (p_binary_op->variant_op < Variant::OP_MAX) { + bool valid = false; + 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 { + ERR_PRINT("Parser bug: unknown binary operation."); } p_binary_op->set_datatype(result); @@ -4242,7 +4240,7 @@ bool GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p GDScriptParser::DataType par_type = p_par_types[i]; GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype(); - if (arg_type.is_variant()) { + if (arg_type.is_variant() && !(par_type.is_hard_type() && par_type.is_variant())) { // Argument can be anything, so this is unsafe. mark_node_unsafe(p_call->arguments[i]); } else if (par_type.is_hard_type() && !is_type_compatible(par_type, arg_type, true)) { diff --git a/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd b/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd new file mode 100644 index 0000000000..211115d9cb --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd @@ -0,0 +1,32 @@ +func variant() -> Variant: return null + +var member_weak = variant() +var member_typed: Variant = variant() +var member_inferred := variant() + +func param_weak(param = variant()) -> void: print(param) +func param_typed(param: Variant = variant()) -> void: print(param) +func param_inferred(param := variant()) -> void: print(param) + +func return_untyped(): return variant() +func return_typed() -> Variant: return variant() + +@warning_ignore(unused_variable) +func test() -> void: + var weak = variant() + var typed: Variant = variant() + var inferred := variant() + + weak = variant() + typed = variant() + inferred = variant() + + param_weak(typed) + param_typed(typed) + param_inferred(typed) + + if typed == null: pass + if typed != null: pass + if typed is Node: pass + + print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/hard_variants.out b/modules/gdscript/tests/scripts/analyzer/features/hard_variants.out new file mode 100644 index 0000000000..08491efa07 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/hard_variants.out @@ -0,0 +1,5 @@ +GDTEST_OK +<null> +<null> +<null> +ok diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs index 0e92f4331d..af83cc24bf 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs @@ -50,6 +50,15 @@ namespace Godot } /// <summary> + /// The volume of this <see cref="Aabb"/>. + /// See also <see cref="HasVolume"/>. + /// </summary> + public readonly real_t Volume + { + get { return _size.X * _size.Y * _size.Z; } + } + + /// <summary> /// Returns an <see cref="Aabb"/> with equivalent position and size, modified so that /// the most-negative corner is the origin and the size is positive. /// </summary> @@ -312,15 +321,6 @@ namespace Godot } /// <summary> - /// Returns the volume of the <see cref="Aabb"/>. - /// </summary> - /// <returns>The volume.</returns> - public readonly real_t GetVolume() - { - return _size.X * _size.Y * _size.Z; - } - - /// <summary> /// Returns a copy of the <see cref="Aabb"/> grown a given amount of units towards all the sides. /// </summary> /// <param name="by">The amount to grow by.</param> @@ -383,7 +383,7 @@ namespace Godot /// Returns <see langword="true"/> if the <see cref="Aabb"/> has /// area, and <see langword="false"/> if the <see cref="Aabb"/> /// is linear, empty, or has a negative <see cref="Size"/>. - /// See also <see cref="GetVolume"/>. + /// See also <see cref="Volume"/>. /// </summary> /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Aabb"/> has volume. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index be4004a0f9..69444f8035 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -51,11 +51,11 @@ namespace Godot /// <summary> /// The area of this <see cref="Rect2"/>. + /// See also <see cref="HasArea"/>. /// </summary> - /// <value>Equivalent to <see cref="GetArea()"/>.</value> public readonly real_t Area { - get { return GetArea(); } + get { return _size.X * _size.Y; } } /// <summary> @@ -161,15 +161,6 @@ namespace Godot } /// <summary> - /// Returns the area of the <see cref="Rect2"/>. - /// </summary> - /// <returns>The area.</returns> - public readonly real_t GetArea() - { - return _size.X * _size.Y; - } - - /// <summary> /// Returns the center of the <see cref="Rect2"/>, which is equal /// to <see cref="Position"/> + (<see cref="Size"/> / 2). /// </summary> @@ -247,7 +238,7 @@ namespace Godot /// Returns <see langword="true"/> if the <see cref="Rect2"/> has /// area, and <see langword="false"/> if the <see cref="Rect2"/> /// is linear, empty, or has a negative <see cref="Size"/>. - /// See also <see cref="GetArea"/>. + /// See also <see cref="Area"/>. /// </summary> /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> has area. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs index 5b06101db5..2099d0abca 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs @@ -51,11 +51,11 @@ namespace Godot /// <summary> /// The area of this <see cref="Rect2I"/>. + /// See also <see cref="HasArea"/>. /// </summary> - /// <value>Equivalent to <see cref="GetArea()"/>.</value> public readonly int Area { - get { return GetArea(); } + get { return _size.X * _size.Y; } } /// <summary> @@ -151,15 +151,6 @@ namespace Godot } /// <summary> - /// Returns the area of the <see cref="Rect2I"/>. - /// </summary> - /// <returns>The area.</returns> - public readonly int GetArea() - { - return _size.X * _size.Y; - } - - /// <summary> /// Returns the center of the <see cref="Rect2I"/>, which is equal /// to <see cref="Position"/> + (<see cref="Size"/> / 2). /// If <see cref="Size"/> is an odd number, the returned center @@ -239,7 +230,7 @@ namespace Godot /// Returns <see langword="true"/> if the <see cref="Rect2I"/> has /// area, and <see langword="false"/> if the <see cref="Rect2I"/> /// is linear, empty, or has a negative <see cref="Size"/>. - /// See also <see cref="GetArea"/>. + /// See also <see cref="Area"/>. /// </summary> /// <returns> /// A <see langword="bool"/> for whether or not the <see cref="Rect2I"/> has area. diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index a09dbd50cf..fd2be9ba22 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -55,6 +55,12 @@ void Shader::set_path(const String &p_path, bool p_take_over) { RS::get_singleton()->shader_set_path_hint(shader, p_path); } +void Shader::set_include_path(const String &p_path) { + // Used only if the shader does not have a resource path set, + // for example during loading stage or when created by code. + include_path = p_path; +} + void Shader::set_code(const String &p_code) { for (Ref<ShaderInclude> E : include_dependencies) { E->disconnect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed)); @@ -80,11 +86,15 @@ void Shader::set_code(const String &p_code) { HashSet<Ref<ShaderInclude>> new_include_dependencies; { + String path = get_path(); + if (path.is_empty()) { + path = include_path; + } // Preprocessor must run here and not in the server because: // 1) Need to keep track of include dependencies at resource level // 2) Server does not do interaction with Resource filetypes, this is a scene level feature. ShaderPreprocessor preprocessor; - preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_include_dependencies); + preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_include_dependencies); } // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) @@ -231,6 +241,7 @@ Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const Strin String str; str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + shader->set_include_path(p_path); shader->set_code(str); if (r_error) { diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 55608b6c11..ca889940ef 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -56,6 +56,7 @@ private: Mode mode = MODE_SPATIAL; HashSet<Ref<ShaderInclude>> include_dependencies; String code; + String include_path; HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures; @@ -72,6 +73,7 @@ public: virtual Mode get_mode() const; virtual void set_path(const String &p_path, bool p_take_over = false) override; + void set_include_path(const String &p_path); void set_code(const String &p_code); String get_code() const; diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp index cd5e9861f7..68137cbec0 100644 --- a/scene/resources/shader_include.cpp +++ b/scene/resources/shader_include.cpp @@ -45,9 +45,14 @@ void ShaderInclude::set_code(const String &p_code) { } { + String path = get_path(); + if (path.is_empty()) { + path = include_path; + } + String pp_code; ShaderPreprocessor preprocessor; - preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_dependencies); + preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_dependencies); } // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) @@ -64,6 +69,10 @@ String ShaderInclude::get_code() const { return code; } +void ShaderInclude::set_include_path(const String &p_path) { + include_path = p_path; +} + void ShaderInclude::_bind_methods() { ClassDB::bind_method(D_METHOD("set_code", "code"), &ShaderInclude::set_code); ClassDB::bind_method(D_METHOD("get_code"), &ShaderInclude::get_code); @@ -86,6 +95,7 @@ Ref<Resource> ResourceFormatLoaderShaderInclude::load(const String &p_path, cons String str; str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + shader_inc->set_include_path(p_path); shader_inc->set_code(str); if (r_error) { diff --git a/scene/resources/shader_include.h b/scene/resources/shader_include.h index 04f4f5cf84..a8949b327e 100644 --- a/scene/resources/shader_include.h +++ b/scene/resources/shader_include.h @@ -42,6 +42,7 @@ class ShaderInclude : public Resource { private: String code; + String include_path; HashSet<Ref<ShaderInclude>> dependencies; void _dependency_changed(); @@ -51,6 +52,8 @@ protected: public: void set_code(const String &p_text); String get_code() const; + + void set_include_path(const String &p_path); }; class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader { diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 816d937e9f..b45a7c0db3 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -674,6 +674,11 @@ void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) { return; } + path = path.simplify_path(); + if (path.is_relative_path()) { + path = state->current_filename.get_base_dir().path_join(path); + } + Ref<Resource> res = ResourceLoader::load(path); if (res.is_null()) { set_error(RTR("Shader include load failed. Does the shader include exist? Is there a cyclic dependency?"), line); |