diff options
Diffstat (limited to 'modules/gdscript/tests/scripts')
49 files changed, 549 insertions, 24 deletions
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_dictionary.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_dictionary.gd new file mode 100644 index 0000000000..c180cca03c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_dictionary.gd @@ -0,0 +1,3 @@ +func test(): + for key: int in { "a": 1 }: + print(key) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_dictionary.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_dictionary.out new file mode 100644 index 0000000000..8530783673 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_dictionary.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot include a value of type "String" as "int". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assign_differently_typed.gd b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assign_differently_typed.gd new file mode 100644 index 0000000000..75d1b7fe62 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assign_differently_typed.gd @@ -0,0 +1,4 @@ +func test(): + var differently: Dictionary[float, float] = { 1.0: 0.0 } + var typed: Dictionary[int, int] = differently + print('not ok') diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assign_differently_typed.out b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assign_differently_typed.out new file mode 100644 index 0000000000..e05d4be8c9 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assign_differently_typed.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a value of type Dictionary[float, float] to variable "typed" with specified type Dictionary[int, int]. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assignment.gd b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assignment.gd new file mode 100644 index 0000000000..e0af71823a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assignment.gd @@ -0,0 +1,2 @@ +func test(): + const dict: Dictionary[int, int] = { "Hello": "World" } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assignment.out b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assignment.out new file mode 100644 index 0000000000..8530783673 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_assignment.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot include a value of type "String" as "int". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_init_with_unconvertible_in_literal.gd b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_init_with_unconvertible_in_literal.gd new file mode 100644 index 0000000000..814ba12aef --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_init_with_unconvertible_in_literal.gd @@ -0,0 +1,4 @@ +func test(): + var unconvertible := 1 + var typed: Dictionary[Object, Object] = { unconvertible: unconvertible } + print('not ok') diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_init_with_unconvertible_in_literal.out b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_init_with_unconvertible_in_literal.out new file mode 100644 index 0000000000..9d6c9d9144 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_init_with_unconvertible_in_literal.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot have a key of type "int" in a dictionary of type "Dictionary[Object, Object]". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_pass_differently_to_typed.gd b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_pass_differently_to_typed.gd new file mode 100644 index 0000000000..73d8ce2b96 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_pass_differently_to_typed.gd @@ -0,0 +1,7 @@ +func expect_typed(typed: Dictionary[int, int]): + print(typed.size()) + +func test(): + var differently: Dictionary[float, float] = { 1.0: 0.0 } + expect_typed(differently) + print('not ok') diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_pass_differently_to_typed.out b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_pass_differently_to_typed.out new file mode 100644 index 0000000000..302109cf8a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_dictionary_pass_differently_to_typed.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid argument for "expect_typed()" function: argument 1 should be "Dictionary[int, int]" but is "Dictionary[float, float]". diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_as_default_parameter.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_as_default_parameter.gd new file mode 100644 index 0000000000..65f5e7da07 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_as_default_parameter.gd @@ -0,0 +1,20 @@ +func print_untyped(dictionary = { 0: 1 }) -> void: + print(dictionary) + print(dictionary.get_typed_key_builtin()) + print(dictionary.get_typed_value_builtin()) + +func print_inferred(dictionary := { 2: 3 }) -> void: + print(dictionary) + print(dictionary.get_typed_key_builtin()) + print(dictionary.get_typed_value_builtin()) + +func print_typed(dictionary: Dictionary[int, int] = { 4: 5 }) -> void: + print(dictionary) + print(dictionary.get_typed_key_builtin()) + print(dictionary.get_typed_value_builtin()) + +func test(): + print_untyped() + print_inferred() + print_typed() + print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_as_default_parameter.out b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_as_default_parameter.out new file mode 100644 index 0000000000..c31561bee3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_as_default_parameter.out @@ -0,0 +1,11 @@ +GDTEST_OK +{ 0: 1 } +0 +0 +{ 2: 3 } +0 +0 +{ 4: 5 } +2 +2 +ok diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_inferred_access_isnt_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_inferred_access_isnt_constant.gd new file mode 100644 index 0000000000..0aa3de2c4a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_inferred_access_isnt_constant.gd @@ -0,0 +1,4 @@ +func test(): + var dict := { 0: 0 } + dict[0] = 1 + print(dict[0]) diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_inferred_access_isnt_constant.out b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_inferred_access_isnt_constant.out new file mode 100644 index 0000000000..a7f1357bb2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_inferred_access_isnt_constant.out @@ -0,0 +1,2 @@ +GDTEST_OK +1 diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd new file mode 100644 index 0000000000..9d3fffd1de --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd @@ -0,0 +1,214 @@ +class A: pass +class B extends A: pass + +enum E { E0 = 391, E1 = 193 } + +func floats_identity(floats: Dictionary[float, float]): return floats + +class Members: + var one: Dictionary[int, int] = { 104: 401 } + var two: Dictionary[int, int] = one + + func check_passing() -> bool: + Utils.check(str(one) == '{ 104: 401 }') + Utils.check(str(two) == '{ 104: 401 }') + two[582] = 285 + Utils.check(str(one) == '{ 104: 401, 582: 285 }') + Utils.check(str(two) == '{ 104: 401, 582: 285 }') + two = { 486: 684 } + Utils.check(str(one) == '{ 104: 401, 582: 285 }') + Utils.check(str(two) == '{ 486: 684 }') + return true + + +@warning_ignore("unsafe_method_access") +@warning_ignore("assert_always_true") +@warning_ignore("return_value_discarded") +func test(): + var untyped_basic = { 459: 954 } + Utils.check(str(untyped_basic) == '{ 459: 954 }') + Utils.check(untyped_basic.get_typed_key_builtin() == TYPE_NIL) + Utils.check(untyped_basic.get_typed_value_builtin() == TYPE_NIL) + + var inferred_basic := { 366: 663 } + Utils.check(str(inferred_basic) == '{ 366: 663 }') + Utils.check(inferred_basic.get_typed_key_builtin() == TYPE_NIL) + Utils.check(inferred_basic.get_typed_value_builtin() == TYPE_NIL) + + var typed_basic: Dictionary = { 521: 125 } + Utils.check(str(typed_basic) == '{ 521: 125 }') + Utils.check(typed_basic.get_typed_key_builtin() == TYPE_NIL) + Utils.check(typed_basic.get_typed_value_builtin() == TYPE_NIL) + + + var empty_floats: Dictionary[float, float] = {} + Utils.check(str(empty_floats) == '{ }') + Utils.check(empty_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(empty_floats.get_typed_value_builtin() == TYPE_FLOAT) + + untyped_basic = empty_floats + Utils.check(untyped_basic.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(untyped_basic.get_typed_value_builtin() == TYPE_FLOAT) + + inferred_basic = empty_floats + Utils.check(inferred_basic.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(inferred_basic.get_typed_value_builtin() == TYPE_FLOAT) + + typed_basic = empty_floats + Utils.check(typed_basic.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(typed_basic.get_typed_value_builtin() == TYPE_FLOAT) + + empty_floats[705.0] = 507.0 + untyped_basic[430.0] = 34.0 + inferred_basic[263.0] = 362.0 + typed_basic[518.0] = 815.0 + Utils.check(str(empty_floats) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') + Utils.check(str(untyped_basic) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') + Utils.check(str(inferred_basic) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') + Utils.check(str(typed_basic) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') + + + const constant_float := 950.0 + const constant_int := 170 + var typed_float := 954.0 + var filled_floats: Dictionary[float, float] = { constant_float: constant_int, typed_float: empty_floats[430.0] + empty_floats[263.0] } + Utils.check(str(filled_floats) == '{ 950: 170, 954: 396 }') + Utils.check(filled_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(filled_floats.get_typed_value_builtin() == TYPE_FLOAT) + + var casted_floats := { empty_floats[263.0] * 2: empty_floats[263.0] / 2 } as Dictionary[float, float] + Utils.check(str(casted_floats) == '{ 724: 181 }') + Utils.check(casted_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(casted_floats.get_typed_value_builtin() == TYPE_FLOAT) + + var returned_floats = (func () -> Dictionary[float, float]: return { 554: 455 }).call() + Utils.check(str(returned_floats) == '{ 554: 455 }') + Utils.check(returned_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(returned_floats.get_typed_value_builtin() == TYPE_FLOAT) + + var passed_floats = floats_identity({ 663.0 if randf() > 0.5 else 663.0: 366.0 if randf() <= 0.5 else 366.0 }) + Utils.check(str(passed_floats) == '{ 663: 366 }') + Utils.check(passed_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(passed_floats.get_typed_value_builtin() == TYPE_FLOAT) + + var default_floats = (func (floats: Dictionary[float, float] = { 364.0: 463.0 }): return floats).call() + Utils.check(str(default_floats) == '{ 364: 463 }') + Utils.check(default_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(default_floats.get_typed_value_builtin() == TYPE_FLOAT) + + var typed_int := 556 + var converted_floats: Dictionary[float, float] = { typed_int: typed_int } + converted_floats[498.0] = 894 + Utils.check(str(converted_floats) == '{ 556: 556, 498: 894 }') + Utils.check(converted_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(converted_floats.get_typed_value_builtin() == TYPE_FLOAT) + + + const constant_basic = { 228: 822 } + Utils.check(str(constant_basic) == '{ 228: 822 }') + Utils.check(constant_basic.get_typed_key_builtin() == TYPE_NIL) + Utils.check(constant_basic.get_typed_value_builtin() == TYPE_NIL) + + const constant_floats: Dictionary[float, float] = { constant_float - constant_basic[228] - constant_int: constant_float + constant_basic[228] + constant_int } + Utils.check(str(constant_floats) == '{ -42: 1942 }') + Utils.check(constant_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(constant_floats.get_typed_value_builtin() == TYPE_FLOAT) + + + var source_floats: Dictionary[float, float] = { 999.74: 47.999 } + untyped_basic = source_floats + var destination_floats: Dictionary[float, float] = untyped_basic + destination_floats[999.74] -= 0.999 + Utils.check(str(source_floats) == '{ 999.74: 47 }') + Utils.check(str(untyped_basic) == '{ 999.74: 47 }') + Utils.check(str(destination_floats) == '{ 999.74: 47 }') + Utils.check(destination_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(destination_floats.get_typed_value_builtin() == TYPE_FLOAT) + + + var duplicated_floats := empty_floats.duplicate() + duplicated_floats.erase(705.0) + duplicated_floats.erase(430.0) + duplicated_floats.erase(518.0) + duplicated_floats[263.0] *= 3 + Utils.check(str(duplicated_floats) == '{ 263: 1086 }') + Utils.check(duplicated_floats.get_typed_key_builtin() == TYPE_FLOAT) + Utils.check(duplicated_floats.get_typed_value_builtin() == TYPE_FLOAT) + + + var b_objects: Dictionary[int, B] = { 0: B.new(), 1: B.new() as A, 2: null } + Utils.check(b_objects.size() == 3) + Utils.check(b_objects.get_typed_value_builtin() == TYPE_OBJECT) + Utils.check(b_objects.get_typed_value_script() == B) + + var a_objects: Dictionary[int, A] = { 0: A.new(), 1: B.new(), 2: null, 3: b_objects[0] } + Utils.check(a_objects.size() == 4) + Utils.check(a_objects.get_typed_value_builtin() == TYPE_OBJECT) + Utils.check(a_objects.get_typed_value_script() == A) + + var a_passed = (func check_a_passing(p_objects: Dictionary[int, A]): return p_objects.size()).call(a_objects) + Utils.check(a_passed == 4) + + var b_passed = (func check_b_passing(basic: Dictionary): return basic[0] != null).call(b_objects) + Utils.check(b_passed == true) + + + var empty_strings: Dictionary[String, String] = {} + var empty_bools: Dictionary[bool, bool] = {} + var empty_basic_one := {} + var empty_basic_two := {} + Utils.check(empty_strings == empty_bools) + Utils.check(empty_basic_one == empty_basic_two) + Utils.check(empty_strings.hash() == empty_bools.hash()) + Utils.check(empty_basic_one.hash() == empty_basic_two.hash()) + + + var assign_source: Dictionary[int, int] = { 527: 725 } + var assign_target: Dictionary[int, int] = {} + assign_target.assign(assign_source) + Utils.check(str(assign_source) == '{ 527: 725 }') + Utils.check(str(assign_target) == '{ 527: 725 }') + assign_source[657] = 756 + Utils.check(str(assign_source) == '{ 527: 725, 657: 756 }') + Utils.check(str(assign_target) == '{ 527: 725 }') + + + var defaults_passed = (func check_defaults_passing(one: Dictionary[int, int] = {}, two := one): + one[887] = 788 + two[198] = 891 + Utils.check(str(one) == '{ 887: 788, 198: 891 }') + Utils.check(str(two) == '{ 887: 788, 198: 891 }') + two = {130: 31} + Utils.check(str(one) == '{ 887: 788, 198: 891 }') + Utils.check(str(two) == '{ 130: 31 }') + return true + ).call() + Utils.check(defaults_passed == true) + + + var members := Members.new() + var members_passed := members.check_passing() + Utils.check(members_passed == true) + + + var typed_enums: Dictionary[E, E] = {} + typed_enums[E.E0] = E.E1 + Utils.check(str(typed_enums) == '{ 391: 193 }') + Utils.check(typed_enums.get_typed_key_builtin() == TYPE_INT) + Utils.check(typed_enums.get_typed_value_builtin() == TYPE_INT) + + const const_enums: Dictionary[E, E] = {} + Utils.check(const_enums.get_typed_key_builtin() == TYPE_INT) + Utils.check(const_enums.get_typed_key_class_name() == &'') + Utils.check(const_enums.get_typed_value_builtin() == TYPE_INT) + Utils.check(const_enums.get_typed_value_class_name() == &'') + + + var a := A.new() + var b := B.new() + var typed_natives: Dictionary[RefCounted, RefCounted] = { a: b } + var typed_scripts = Dictionary(typed_natives, TYPE_OBJECT, "RefCounted", A, TYPE_OBJECT, "RefCounted", B) + Utils.check(typed_scripts[a] == b) + + + print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.out b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_with_custom_class.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_with_custom_class.gd new file mode 100644 index 0000000000..f4a23ade14 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_with_custom_class.gd @@ -0,0 +1,9 @@ +class Inner: + var prop = "Inner" + +var dict: Dictionary[int, Inner] = { 0: Inner.new() } + + +func test(): + var element: Inner = dict[0] + print(element.prop) diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_with_custom_class.out b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_with_custom_class.out new file mode 100644 index 0000000000..8f250d2632 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_with_custom_class.out @@ -0,0 +1,2 @@ +GDTEST_OK +Inner diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd index d937dfdcfe..37f118dc5d 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd +++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd @@ -1,12 +1,29 @@ -signal s1() -signal s2() -signal s3() +# Doesn't produce the warning: +signal used_as_first_class_signal() +signal used_with_signal_constructor() +signal used_with_signal_emit() +signal used_with_object_emit_signal() +signal used_with_object_connect() +signal used_with_object_disconnect() +signal used_with_self_prefix() + +# Produce the warning: +signal used_with_dynamic_name() +signal just_unused() @warning_ignore("unused_signal") -signal s4() +signal unused_but_ignored() func no_exec(): - s1.emit() - print(s2) + print(used_as_first_class_signal) + print(Signal(self, "used_with_signal_constructor")) + used_with_signal_emit.emit() + print(emit_signal("used_with_object_emit_signal")) + print(connect("used_with_object_connect", Callable())) + disconnect("used_with_object_disconnect", Callable()) + print(self.emit_signal("used_with_self_prefix")) + + var dynamic_name := "used_with_dynamic_name" + print(emit_signal(dynamic_name)) func test(): pass diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out index ff57017830..39ddf91c76 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out @@ -1,5 +1,9 @@ GDTEST_OK >> WARNING ->> Line: 3 +>> Line: 11 >> UNUSED_SIGNAL ->> The signal "s3" is declared but never explicitly used in the class. +>> The signal "used_with_dynamic_name" is declared but never explicitly used in the class. +>> WARNING +>> Line: 12 +>> UNUSED_SIGNAL +>> The signal "just_unused" is declared but never explicitly used in the class. diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg new file mode 100644 index 0000000000..e4759ac76b --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg @@ -0,0 +1,19 @@ +[output] +include=[ + {"display": "new"}, + {"display": "SIZE_EXPAND"}, + {"display": "SIZE_EXPAND_FILL"}, + {"display": "SIZE_FILL"}, + {"display": "SIZE_SHRINK_BEGIN"}, + {"display": "SIZE_SHRINK_CENTER"}, + {"display": "SIZE_SHRINK_END"}, +] +exclude=[ + {"display": "Control.SIZE_EXPAND"}, + {"display": "Control.SIZE_EXPAND_FILL"}, + {"display": "Control.SIZE_FILL"}, + {"display": "Control.SIZE_SHRINK_BEGIN"}, + {"display": "Control.SIZE_SHRINK_CENTER"}, + {"display": "Control.SIZE_SHRINK_END"}, + {"display": "contro_var"} +] diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.gd b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.gd new file mode 100644 index 0000000000..4aeafb2e0a --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.gd @@ -0,0 +1,7 @@ +extends Control + +var contro_var + +func _ready(): + size_flags_horizontal = Control.➡ + pass diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg new file mode 100644 index 0000000000..e4759ac76b --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg @@ -0,0 +1,19 @@ +[output] +include=[ + {"display": "new"}, + {"display": "SIZE_EXPAND"}, + {"display": "SIZE_EXPAND_FILL"}, + {"display": "SIZE_FILL"}, + {"display": "SIZE_SHRINK_BEGIN"}, + {"display": "SIZE_SHRINK_CENTER"}, + {"display": "SIZE_SHRINK_END"}, +] +exclude=[ + {"display": "Control.SIZE_EXPAND"}, + {"display": "Control.SIZE_EXPAND_FILL"}, + {"display": "Control.SIZE_FILL"}, + {"display": "Control.SIZE_SHRINK_BEGIN"}, + {"display": "Control.SIZE_SHRINK_CENTER"}, + {"display": "Control.SIZE_SHRINK_END"}, + {"display": "contro_var"} +] diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.gd b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.gd new file mode 100644 index 0000000000..47e9bd5a67 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.gd @@ -0,0 +1,7 @@ +extends Control + +var contro_var + +func _ready(): + size_flags_horizontal = Control.SIZE➡ + pass diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_identifier.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_identifier.cfg new file mode 100644 index 0000000000..5cc4ec5fd3 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_identifier.cfg @@ -0,0 +1,12 @@ +[output] +include=[ + {"display": "Control.SIZE_EXPAND"}, + {"display": "Control.SIZE_EXPAND_FILL"}, + {"display": "Control.SIZE_FILL"}, + {"display": "Control.SIZE_SHRINK_BEGIN"}, + {"display": "Control.SIZE_SHRINK_CENTER"}, + {"display": "Control.SIZE_SHRINK_END"}, +] +exclude=[ + {"display": "contro_var"} +] diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_identifier.gd b/modules/gdscript/tests/scripts/completion/assignment_options/enum_identifier.gd new file mode 100644 index 0000000000..5c96720bd3 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_identifier.gd @@ -0,0 +1,7 @@ +extends Control + +var contro_var + +func _ready(): + size_flags_horizontal = Con➡ + pass diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_no_identifier.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_no_identifier.cfg new file mode 100644 index 0000000000..5cc4ec5fd3 --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_no_identifier.cfg @@ -0,0 +1,12 @@ +[output] +include=[ + {"display": "Control.SIZE_EXPAND"}, + {"display": "Control.SIZE_EXPAND_FILL"}, + {"display": "Control.SIZE_FILL"}, + {"display": "Control.SIZE_SHRINK_BEGIN"}, + {"display": "Control.SIZE_SHRINK_CENTER"}, + {"display": "Control.SIZE_SHRINK_END"}, +] +exclude=[ + {"display": "contro_var"} +] diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_no_identifier.gd b/modules/gdscript/tests/scripts/completion/assignment_options/enum_no_identifier.gd new file mode 100644 index 0000000000..d8bf13e51d --- /dev/null +++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_no_identifier.gd @@ -0,0 +1,7 @@ +extends Control + +var contro_var + +func _ready(): + size_flags_horizontal = ➡ + pass diff --git a/modules/gdscript/tests/scripts/parser/features/typed_dictionaries.gd b/modules/gdscript/tests/scripts/parser/features/typed_dictionaries.gd new file mode 100644 index 0000000000..57e6489484 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/typed_dictionaries.gd @@ -0,0 +1,5 @@ +func test(): + var my_dictionary: Dictionary[int, String] = { 1: "one", 2: "two", 3: "three" } + var inferred_dictionary := { 1: "one", 2: "two", 3: "three" } # This is Dictionary[int, String]. + print(my_dictionary) + print(inferred_dictionary) diff --git a/modules/gdscript/tests/scripts/parser/features/typed_dictionaries.out b/modules/gdscript/tests/scripts/parser/features/typed_dictionaries.out new file mode 100644 index 0000000000..6021c338ee --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/typed_dictionaries.out @@ -0,0 +1,3 @@ +GDTEST_OK +{ 1: "one", 2: "two", 3: "three" } +{ 1: "one", 2: "two", 3: "three" } diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_basic_to_typed.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_basic_to_typed.gd new file mode 100644 index 0000000000..75004742a2 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_basic_to_typed.gd @@ -0,0 +1,4 @@ +func test(): + var basic := { 1: 1 } + var typed: Dictionary[int, int] = basic + print('not ok') diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_basic_to_typed.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_basic_to_typed.out new file mode 100644 index 0000000000..cadb17f570 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_basic_to_typed.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/typed_dictionary_assign_basic_to_typed.gd +>> 3 +>> Trying to assign a dictionary of type "Dictionary" to a variable of type "Dictionary[int, int]". diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed.gd new file mode 100644 index 0000000000..e5ab4a1a85 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed.gd @@ -0,0 +1,4 @@ +func test(): + var differently: Variant = { 1.0: 0.0 } as Dictionary[float, float] + var typed: Dictionary[int, int] = differently + print('not ok') diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed.out new file mode 100644 index 0000000000..fe1e5d1285 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/typed_dictionary_assign_differently_typed.gd +>> 3 +>> Trying to assign a dictionary of type "Dictionary[float, float]" to a variable of type "Dictionary[int, int]". diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_wrong_to_typed.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_wrong_to_typed.gd new file mode 100644 index 0000000000..6cc0e57255 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_wrong_to_typed.gd @@ -0,0 +1,7 @@ +class Foo: pass +class Bar extends Foo: pass +class Baz extends Foo: pass + +func test(): + var typed: Dictionary[Bar, Bar] = { Baz.new() as Foo: Baz.new() as Foo } + print('not ok') diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_wrong_to_typed.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_wrong_to_typed.out new file mode 100644 index 0000000000..18a4c360e2 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_wrong_to_typed.out @@ -0,0 +1,5 @@ +GDTEST_RUNTIME_ERROR +>> ERROR +>> Method/function failed. +>> Unable to convert key from "Object" to "Object". +not ok diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_basic_to_typed.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_basic_to_typed.gd new file mode 100644 index 0000000000..8f7d732584 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_basic_to_typed.gd @@ -0,0 +1,7 @@ +func expect_typed(typed: Dictionary[int, int]): + print(typed.size()) + +func test(): + var basic := { 1: 1 } + expect_typed(basic) + print('not ok') diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_basic_to_typed.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_basic_to_typed.out new file mode 100644 index 0000000000..fb45461701 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_basic_to_typed.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/typed_dictionary_pass_basic_to_typed.gd +>> 6 +>> Invalid type in function 'expect_typed' in base 'RefCounted (typed_dictionary_pass_basic_to_typed.gd)'. The dictionary of argument 1 (Dictionary) does not have the same element type as the expected typed dictionary argument. diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_differently_to_typed.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_differently_to_typed.gd new file mode 100644 index 0000000000..978a9fdfee --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_differently_to_typed.gd @@ -0,0 +1,7 @@ +func expect_typed(typed: Dictionary[int, int]): + print(typed.size()) + +func test(): + var differently: Variant = { 1.0: 0.0 } as Dictionary[float, float] + expect_typed(differently) + print('not ok') diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_differently_to_typed.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_differently_to_typed.out new file mode 100644 index 0000000000..4036a1bf01 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_pass_differently_to_typed.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/typed_dictionary_pass_differently_to_typed.gd +>> 6 +>> Invalid type in function 'expect_typed' in base 'RefCounted (typed_dictionary_pass_differently_to_typed.gd)'. The dictionary of argument 1 (Dictionary[float, float]) does not have the same element type as the expected typed dictionary argument. diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd index bc899a3a6f..393500bd9b 100644 --- a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd +++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd @@ -28,13 +28,18 @@ func test(): prints(var_to_str(e), var_to_str(elem)) print("Test String-keys dictionary.") - var d1 := {a = 1, b = 2, c = 3} + var d1 := { a = 1, b = 2, c = 3 } for k: StringName in d1: var key := k prints(var_to_str(k), var_to_str(key)) print("Test RefCounted-keys dictionary.") - var d2 := {RefCounted.new(): 1, Resource.new(): 2, ConfigFile.new(): 3} + var d2 := { RefCounted.new(): 1, Resource.new(): 2, ConfigFile.new(): 3 } for k: RefCounted in d2: var key := k prints(k.get_class(), key.get_class()) + + print("Test implicitly typed dictionary literal.") + for k: StringName in { x = 123, y = 456, z = 789 }: + var key := k + prints(var_to_str(k), var_to_str(key)) diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out index eeebdc4be5..89cc1b76fe 100644 --- a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out +++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out @@ -27,3 +27,7 @@ Test RefCounted-keys dictionary. RefCounted RefCounted Resource Resource ConfigFile ConfigFile +Test implicitly typed dictionary literal. +&"x" &"x" +&"y" &"y" +&"z" &"z" diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd index 91d5a501c8..4ce53aa395 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.gd +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd @@ -31,6 +31,16 @@ var test_var_hard_array_my_enum: Array[MyEnum] var test_var_hard_array_resource: Array[Resource] var test_var_hard_array_this: Array[TestMemberInfo] var test_var_hard_array_my_class: Array[MyClass] +var test_var_hard_dictionary: Dictionary +var test_var_hard_dictionary_int_variant: Dictionary[int, Variant] +var test_var_hard_dictionary_variant_int: Dictionary[Variant, int] +var test_var_hard_dictionary_int_int: Dictionary[int, int] +var test_var_hard_dictionary_variant_type: Dictionary[Variant.Type, Variant.Type] +var test_var_hard_dictionary_node_process_mode: Dictionary[Node.ProcessMode, Node.ProcessMode] +var test_var_hard_dictionary_my_enum: Dictionary[MyEnum, MyEnum] +var test_var_hard_dictionary_resource: Dictionary[Resource, Resource] +var test_var_hard_dictionary_this: Dictionary[TestMemberInfo, TestMemberInfo] +var test_var_hard_dictionary_my_class: Dictionary[MyClass, MyClass] var test_var_hard_resource: Resource var test_var_hard_this: TestMemberInfo var test_var_hard_my_class: MyClass @@ -43,17 +53,17 @@ func test_func_weak_null(): return null func test_func_weak_int(): return 1 func test_func_hard_variant() -> Variant: return null func test_func_hard_int() -> int: return 1 -func test_func_args_1(_a: int, _b: Array[int], _c: int = 1, _d = 2): pass +func test_func_args_1(_a: int, _b: Array[int], _c: Dictionary[int, int], _d: int = 1, _e = 2): pass func test_func_args_2(_a = 1, _b = _a, _c = [2], _d = 3): pass signal test_signal_1() signal test_signal_2(a: Variant, b) -signal test_signal_3(a: int, b: Array[int]) -signal test_signal_4(a: Variant.Type, b: Array[Variant.Type]) -signal test_signal_5(a: MyEnum, b: Array[MyEnum]) -signal test_signal_6(a: Resource, b: Array[Resource]) -signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo]) -signal test_signal_8(a: MyClass, b: Array[MyClass]) +signal test_signal_3(a: int, b: Array[int], c: Dictionary[int, int]) +signal test_signal_4(a: Variant.Type, b: Array[Variant.Type], c: Dictionary[Variant.Type, Variant.Type]) +signal test_signal_5(a: MyEnum, b: Array[MyEnum], c: Dictionary[MyEnum, MyEnum]) +signal test_signal_6(a: Resource, b: Array[Resource], c: Dictionary[Resource, Resource]) +signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo], c: Dictionary[TestMemberInfo, TestMemberInfo]) +signal test_signal_8(a: MyClass, b: Array[MyClass], c: Dictionary[MyClass, MyClass]) func no_exec(): test_signal_1.emit() diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.out b/modules/gdscript/tests/scripts/runtime/features/member_info.out index 7c826ac05a..2baf451aa5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.out +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.out @@ -23,6 +23,16 @@ var test_var_hard_array_my_enum: Array[TestMemberInfo.MyEnum] var test_var_hard_array_resource: Array[Resource] var test_var_hard_array_this: Array[TestMemberInfo] var test_var_hard_array_my_class: Array[RefCounted] +var test_var_hard_dictionary: Dictionary +var test_var_hard_dictionary_int_variant: Dictionary[int, Variant] +var test_var_hard_dictionary_variant_int: Dictionary[Variant, int] +var test_var_hard_dictionary_int_int: Dictionary[int, int] +var test_var_hard_dictionary_variant_type: Dictionary[Variant.Type, Variant.Type] +var test_var_hard_dictionary_node_process_mode: Dictionary[Node.ProcessMode, Node.ProcessMode] +var test_var_hard_dictionary_my_enum: Dictionary[TestMemberInfo.MyEnum, TestMemberInfo.MyEnum] +var test_var_hard_dictionary_resource: Dictionary[Resource, Resource] +var test_var_hard_dictionary_this: Dictionary[TestMemberInfo, TestMemberInfo] +var test_var_hard_dictionary_my_class: Dictionary[RefCounted, RefCounted] var test_var_hard_resource: Resource var test_var_hard_this: TestMemberInfo var test_var_hard_my_class: RefCounted @@ -33,13 +43,13 @@ func test_func_weak_null() -> Variant func test_func_weak_int() -> Variant func test_func_hard_variant() -> Variant func test_func_hard_int() -> int -func test_func_args_1(_a: int, _b: Array[int], _c: int = 1, _d: Variant = 2) -> void +func test_func_args_1(_a: int, _b: Array[int], _c: Dictionary[int, int], _d: int = 1, _e: Variant = 2) -> void func test_func_args_2(_a: Variant = 1, _b: Variant = null, _c: Variant = null, _d: Variant = 3) -> void signal test_signal_1() signal test_signal_2(a: Variant, b: Variant) -signal test_signal_3(a: int, b: Array[int]) -signal test_signal_4(a: Variant.Type, b: Array[Variant.Type]) -signal test_signal_5(a: TestMemberInfo.MyEnum, b: Array[TestMemberInfo.MyEnum]) -signal test_signal_6(a: Resource, b: Array[Resource]) -signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo]) -signal test_signal_8(a: RefCounted, b: Array[RefCounted]) +signal test_signal_3(a: int, b: Array[int], c: Dictionary[int, int]) +signal test_signal_4(a: Variant.Type, b: Array[Variant.Type], c: Dictionary[Variant.Type, Variant.Type]) +signal test_signal_5(a: TestMemberInfo.MyEnum, b: Array[TestMemberInfo.MyEnum], c: Dictionary[TestMemberInfo.MyEnum, TestMemberInfo.MyEnum]) +signal test_signal_6(a: Resource, b: Array[Resource], c: Dictionary[Resource, Resource]) +signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo], c: Dictionary[TestMemberInfo, TestMemberInfo]) +signal test_signal_8(a: RefCounted, b: Array[RefCounted], c: Dictionary[RefCounted, RefCounted]) diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_implicit_cast_param.gd b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_implicit_cast_param.gd new file mode 100644 index 0000000000..0371ee5630 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_implicit_cast_param.gd @@ -0,0 +1,6 @@ +func test_param(dictionary: Dictionary[int, String]) -> void: + print(dictionary.get_typed_key_builtin() == TYPE_INT) + print(dictionary.get_typed_value_builtin() == TYPE_STRING) + +func test() -> void: + test_param({ 123: "some_string" }) diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_implicit_cast_param.out b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_implicit_cast_param.out new file mode 100644 index 0000000000..9d111a8322 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_implicit_cast_param.out @@ -0,0 +1,3 @@ +GDTEST_OK +true +true diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_init_with_untyped_in_literal.gd b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_init_with_untyped_in_literal.gd new file mode 100644 index 0000000000..ee51440d80 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_init_with_untyped_in_literal.gd @@ -0,0 +1,7 @@ +func test(): + var untyped: Variant = 32 + var typed: Dictionary[int, int] = { untyped: untyped } + Utils.check(typed.get_typed_key_builtin() == TYPE_INT) + Utils.check(typed.get_typed_value_builtin() == TYPE_INT) + Utils.check(str(typed) == '{ 32: 32 }') + print('ok') diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_init_with_untyped_in_literal.out b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_init_with_untyped_in_literal.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/typed_dictionary_init_with_untyped_in_literal.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index 5d615d8557..1e2788f765 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -24,6 +24,11 @@ static func get_type(property: Dictionary, is_return: bool = false) -> String: if str(property.hint_string).is_empty(): return "Array[<unknown type>]" return "Array[%s]" % property.hint_string + TYPE_DICTIONARY: + if property.hint == PROPERTY_HINT_DICTIONARY_TYPE: + if str(property.hint_string).is_empty(): + return "Dictionary[<unknown type>, <unknown type>]" + return "Dictionary[%s]" % str(property.hint_string).replace(";", ", ") TYPE_OBJECT: if not str(property.class_name).is_empty(): return property.class_name @@ -188,6 +193,8 @@ static func get_property_hint_name(hint: PropertyHint) -> String: return "PROPERTY_HINT_INT_IS_POINTER" PROPERTY_HINT_ARRAY_TYPE: return "PROPERTY_HINT_ARRAY_TYPE" + PROPERTY_HINT_DICTIONARY_TYPE: + return "PROPERTY_HINT_DICTIONARY_TYPE" PROPERTY_HINT_LOCALE_ID: return "PROPERTY_HINT_LOCALE_ID" PROPERTY_HINT_LOCALIZABLE_STRING: |