From bf4c90c77782603d8e774675518b2c85e2ac8d6c Mon Sep 17 00:00:00 2001 From: Chia-Hsiang Cheng Date: Thu, 18 Jan 2024 12:28:57 +0800 Subject: [PATCH] Determine if a utility function is pure --- core/variant/variant.h | 1 + core/variant/variant_utility.cpp | 269 ++++++++++-------- modules/gdscript/gdscript_analyzer.cpp | 2 +- .../scripts/analyzer/features/const_call.gd | 33 +++ .../scripts/analyzer/features/const_call.out | 2 + 5 files changed, 184 insertions(+), 123 deletions(-) create mode 100644 modules/gdscript/tests/scripts/analyzer/features/const_call.gd create mode 100644 modules/gdscript/tests/scripts/analyzer/features/const_call.out diff --git a/core/variant/variant.h b/core/variant/variant.h index 602d287f224a..8bab3d81b23d 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -754,6 +754,7 @@ class Variant { static bool has_utility_function_return_value(const StringName &p_name); static Variant::Type get_utility_function_return_type(const StringName &p_name); static bool is_utility_function_vararg(const StringName &p_name); + static bool is_utility_function_const(const StringName &p_name); // For GDScript. Compile time constant. This is **not** `const` qualifier. static uint32_t get_utility_function_hash(const StringName &p_name); static void get_utility_function_list(List *r_functions); diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index cc48394b64c6..ce81db2efcf8 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -1337,7 +1337,7 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return Variant::NIL; } -#define FUNCBINDR(m_func, m_args, m_category) \ +#define FUNCBINDR(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1362,11 +1362,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return true; \ } \ static bool is_vararg() { return false; } \ + static bool is_const() { return m_is_const; } \ static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBINDVR(m_func, m_args, m_category) \ +#define FUNCBINDVR(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1394,11 +1395,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return true; \ } \ static bool is_vararg() { return false; } \ + static bool is_const() { return m_is_const; } \ static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBINDVR2(m_func, m_args, m_category) \ +#define FUNCBINDVR2(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1428,11 +1430,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return true; \ } \ static bool is_vararg() { return false; } \ + static bool is_const() { return m_is_const; } \ static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBINDVR3(m_func, m_args, m_category) \ +#define FUNCBINDVR3(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1462,11 +1465,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return true; \ } \ static bool is_vararg() { return false; } \ + static bool is_const() { return m_is_const; } \ static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBINDVARARG(m_func, m_args, m_category) \ +#define FUNCBINDVARARG(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1505,13 +1509,16 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { \ return true; \ } \ + static bool is_const() { \ + return m_is_const; \ + } \ static Variant::UtilityFunctionType get_type() { \ return m_category; \ } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBINDVARARGS(m_func, m_args, m_category) \ +#define FUNCBINDVARARGS(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1550,13 +1557,16 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { \ return true; \ } \ + static bool is_const() { \ + return m_is_const; \ + } \ static Variant::UtilityFunctionType get_type() { \ return m_category; \ } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBINDVARARGV(m_func, m_args, m_category) \ +#define FUNCBINDVARARGV(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1594,13 +1604,16 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { \ return true; \ } \ + static bool is_const() { \ + return m_is_const; \ + } \ static Variant::UtilityFunctionType get_type() { \ return m_category; \ } \ }; \ register_utility_function(#m_func, m_args) -#define FUNCBIND(m_func, m_args, m_category) \ +#define FUNCBIND(m_func, m_args, m_is_const, m_category) \ class Func_##m_func { \ public: \ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ @@ -1625,6 +1638,7 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return false; \ } \ static bool is_vararg() { return false; } \ + static bool is_const() { return m_is_const; } \ static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ register_utility_function(#m_func, m_args) @@ -1635,6 +1649,7 @@ struct VariantUtilityFunctionInfo { Variant::PTRUtilityFunction ptr_call_utility = nullptr; Vector argnames; bool is_vararg = false; + bool is_const = false; bool returns_value = false; int argcount = 0; Variant::Type (*get_arg_type)(int) = nullptr; @@ -1659,6 +1674,7 @@ static void register_utility_function(const String &p_name, const Vector bfi.validated_call_utility = T::validated_call; bfi.ptr_call_utility = T::ptrcall; bfi.is_vararg = T::is_vararg(); + bfi.is_const = T::is_const(); bfi.argnames = argnames; bfi.argcount = T::get_argument_count(); if (!bfi.is_vararg) { @@ -1676,156 +1692,156 @@ static void register_utility_function(const String &p_name, const Vector void Variant::_register_variant_utility_functions() { // Math - FUNCBINDR(sin, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(cos, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(tan, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sin, sarray("angle_rad"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cos, sarray("angle_rad"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(tan, sarray("angle_rad"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(sinh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(cosh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(tanh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sinh, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cosh, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(tanh, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(asin, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(acos, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(atan, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(asin, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(acos, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(atan, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(atan2, sarray("y", "x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(atan2, sarray("y", "x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(asinh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(acosh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(atanh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(asinh, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(acosh, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(atanh, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(posmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sqrt, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(fmod, sarray("x", "y"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(fposmod, sarray("x", "y"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(posmod, sarray("x", "y"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(floorf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(floori, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR(floor, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(floorf, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(floori, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(ceilf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(ceili, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR(ceil, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(ceilf, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(ceili, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(roundf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(roundi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR(round, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(roundf, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(roundi, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(absf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(absi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR(abs, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(absf, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(absi, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR(sign, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(signf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(signi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR(sign, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(signf, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(signi, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR2(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(snappedf, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(snappedi, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR2(snapped, sarray("x", "step"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(snappedf, sarray("x", "step"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(snappedi, sarray("x", "step"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(pow, sarray("base", "exp"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(log, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(exp, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(pow, sarray("base", "exp"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(log, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(exp, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_nan, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_inf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_nan, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_inf, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(is_finite, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_equal_approx, sarray("a", "b"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_zero_approx, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(is_finite, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(ease, sarray("x", "curve"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(step_decimals, sarray("x"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR3(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(lerpf, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(cubic_interpolate_angle, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(bezier_derivative, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(angle_difference, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR3(lerp, sarray("from", "to", "weight"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(lerpf, sarray("from", "to", "weight"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cubic_interpolate_angle, sarray("from", "to", "pre", "post", "weight"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(bezier_derivative, sarray("start", "control_1", "control_2", "end", "t"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(angle_difference, sarray("from", "to"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(rotate_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(smoothstep, sarray("from", "to", "x"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(move_toward, sarray("from", "to", "delta"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(rotate_toward, sarray("from", "to", "delta"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(deg_to_rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(rad_to_deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(linear_to_db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(db_to_linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(deg_to_rad, sarray("deg"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(rad_to_deg, sarray("rad"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(linear_to_db, sarray("lin"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(db_to_linear, sarray("db"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR3(wrap, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR3(wrap, sarray("value", "min", "max"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(wrapi, sarray("value", "min", "max"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(wrapf, sarray("value", "min", "max"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVARARG(max, sarray(), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(maxi, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(maxf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVARARG(max, sarray(), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(maxi, sarray("a", "b"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(maxf, sarray("a", "b"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVARARG(min, sarray(), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(mini, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(minf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVARARG(min, sarray(), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(mini, sarray("a", "b"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(minf, sarray("a", "b"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDVR3(clamp, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(clampi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(clampf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDVR3(clamp, sarray("value", "min", "max"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(clampi, sarray("value", "min", "max"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(clampf, sarray("value", "min", "max"), true, Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH); - FUNCBINDR(pingpong, sarray("value", "length"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(nearest_po2, sarray("value"), true, Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(pingpong, sarray("value", "length"), true, Variant::UTILITY_FUNC_TYPE_MATH); // Random - FUNCBIND(randomize, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(randi, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(randf, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(randi_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(randf_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(randfn, sarray("mean", "deviation"), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBIND(seed, sarray("base"), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(rand_from_seed, sarray("seed"), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBIND(randomize, sarray(), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randi, sarray(), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randf, sarray(), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randi_range, sarray("from", "to"), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randf_range, sarray("from", "to"), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(randfn, sarray("mean", "deviation"), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBIND(seed, sarray("base"), false, Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDR(rand_from_seed, sarray("seed"), false, Variant::UTILITY_FUNC_TYPE_RANDOM); // Utility - FUNCBINDVR(weakref, sarray("obj"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(_typeof, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(type_convert, sarray("variant", "type"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(error_string, sarray("error"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(type_string, sarray("type"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(print_rich, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(printerr, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(printt, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(prints, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(printraw, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(print_verbose, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(push_error, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDVARARGV(push_warning, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVR(weakref, sarray("obj"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(_typeof, sarray("variable"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(type_convert, sarray("variant", "type"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGS(str, sarray(), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(error_string, sarray("error"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(type_string, sarray("type"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(print, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(print_rich, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(printerr, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(printt, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(prints, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(printraw, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(print_verbose, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(push_error, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDVARARGV(push_warning, sarray(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(var_to_str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(str_to_var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(var_to_str, sarray("variable"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(str_to_var, sarray("string"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(var_to_bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(bytes_to_var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(var_to_bytes, sarray("variable"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(bytes_to_var, sarray("bytes"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(var_to_bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(bytes_to_var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(var_to_bytes_with_objects, sarray("variable"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(bytes_to_var_with_objects, sarray("bytes"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(hash, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(hash, sarray("variable"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(instance_from_id, sarray("instance_id"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(is_instance_id_valid, sarray("id"), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(is_instance_valid, sarray("instance"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(instance_from_id, sarray("instance_id"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(is_instance_id_valid, sarray("id"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(is_instance_valid, sarray("instance"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(rid_allocate_id, Vector(), Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(rid_from_int64, sarray("base"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(rid_allocate_id, Vector(), false, Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(rid_from_int64, sarray("base"), true, Variant::UTILITY_FUNC_TYPE_GENERAL); - FUNCBINDR(is_same, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_GENERAL); + FUNCBINDR(is_same, sarray("a", "b"), false, Variant::UTILITY_FUNC_TYPE_GENERAL); } void Variant::_unregister_variant_utility_functions() { @@ -1964,6 +1980,15 @@ bool Variant::is_utility_function_vararg(const StringName &p_name) { return bfi->is_vararg; } +bool Variant::is_utility_function_const(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + if (!bfi) { + return false; + } + + return bfi->is_const; +} + uint32_t Variant::get_utility_function_hash(const StringName &p_name) { const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); ERR_FAIL_NULL_V(bfi, 0); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 3fd5b3f519d4..754e705d625b 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -3192,7 +3192,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a 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) { + if (all_is_constant && Variant::is_utility_function_const(function_name)) { // Can call on compilation. Vector args; for (int i = 0; i < p_call->arguments.size(); i++) { diff --git a/modules/gdscript/tests/scripts/analyzer/features/const_call.gd b/modules/gdscript/tests/scripts/analyzer/features/const_call.gd new file mode 100644 index 000000000000..9a2a3a575337 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/const_call.gd @@ -0,0 +1,33 @@ +const type_of_int: int = typeof(1) +const type_of_float: int = typeof(3.14) + +const str_int: String = str(18) +const str_plus: String = str(13) + str(29) + +const err_ok: String = error_string(OK) +const err_busy: String = error_string(ERR_BUSY) + +const v_to_s: String = var_to_str(32) + +const v_to_b: PackedByteArray = var_to_bytes(32) + +const v_to_b_objs: PackedByteArray = var_to_bytes_with_objects(64) + +const const_rid: RID = rid_from_int64(0) + +@warning_ignore("assert_always_true") +func test(): + assert(type_of_int == TYPE_INT) + assert(type_of_float == TYPE_FLOAT) + + assert(str_int == '18') + assert(str_plus == '1329') + + assert(err_ok == "OK") + assert(err_busy == "Busy") + + assert(v_to_s == "32") + + assert(const_rid.get_id() == 0) + + print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/const_call.out b/modules/gdscript/tests/scripts/analyzer/features/const_call.out new file mode 100644 index 000000000000..1b47ed10dc06 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/const_call.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok