Description
Tested versions
v4.3.stable.official [77dcf97]
System information
Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2060 (NVIDIA; 32.0.15.6636) - AMD Ryzen 5 7600X 6-Core Processor (12 Threads)
Issue description
v4.3.stable.official [77dcf97]
The recently added static typing for for loop variables here #80247 has a weird quirk that I feel like I may be considered a bug, or at least strange behavior.
If you are looping over an array that contains node references, and one of those nodes gets freed, <Freed Object>
remains in its index. While normally you can use is_instance_valid()
for validating your node references, trying to do this in a typed for loop will fail with the error "Trying to assign invalid previously freed instance" at the "for" line, before it even gets to where you can validate it. However, it's possible to get around this by removing the type from the loop variable and checking it after the instance is validated, but that then makes typing the loop variable questionable in the first place. Since I think that may be unclear, here's some example code of what I mean:
# Tested with an Array with some generic Node2Ds
var objects_to_be_freed: Array = get_tree().get_nodes_in_group("object_freeing")
# After any of those nodes is freed...
# Runs without error
for object in objects_to_be_freed:
if is_instance_valid(object):
print("Valid!")
else:
print("Invalid!")
# Will cause error: "Trying to assign invalid previously freed instance"
for object: Node2D in objects_to_be_freed: # Errors at this line
if is_instance_valid(object): # I would expect this line to be how to catch the invalid reference before error
print("Valid!")
else:
print("Invalid!")
# Runs without error and effectively keeps static typing as far as I can tell
for object in objects_to_be_freed:
if is_instance_valid(object) and object is Node2D:
print("Valid!")
else:
print("Invalid!")
This makes me wonder if this behavior is intended, and if it is intended, why? The 3rd block (the workaround) seems like it would be the best way to handle this in all cases, and if that's the case, then why isn't the first block just interpreted the same way by the engine?
I would expect the first block to work without error as written, simply printing "Invalid!" if the object was freed.
Steps to reproduce
Make an array, add node references to it, free any of the nodes without clearing the reference, create a for loop to iterate over that array, and make the for loop variable typed to those nodes. Tested this with the code snippet in the issue description.
Minimal reproduction project (MRP)
N/A
Metadata
Metadata
Assignees
Type
Projects
Status
For team assessment
Activity