Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoload global variables behaving inconsistently, properties not having types inferred #77643

Open
nazjun opened this issue May 30, 2023 · 3 comments

Comments

@nazjun
Copy link

nazjun commented May 30, 2023

Godot version

v4.0.3.stable.mono.official [5222a99]

System information

  • OS: Windows 11
  • Godot Version: 4.0.3.stable.mono
  • Rendering Driver: Any
  • Rendering Method: Any

Issue description

I've noticed some strange behaviors arising from the use of static typing (along with type casting in general) with autoload global variables.

Here are my findings so far:

  • Creating an autoload from a .tscn file will cause the singleton node referenced by the global variable to be unconvertible to the type of the script specified after class_name, if it exists.
  • Creating an autoload from a .gd file, however, does allow the variable to be converted to the custom type.
  • Properties of custom reference types in an autoload will not be inferred with the := operator if the autoload is .tscn-based, but will if it is .gd-based.
  • Properties of custom reference types in an autoload class will not have their own custom properties appear in the auto-completion menu, if the autoload is accessed with its global variable. The auto-completion menu will only reflect the built-in classes they're derived from. Creating a variable of the singleton's custom type (which is only possible with .gd autoloads) and then accessing the reference property that way is the only way I can find that allows the auto-completion to accurately reflect the current type of the reference.

The best way I can work around this while maintaining type safety is by only using .gd-based autoloads, but unless I store an explicit reference to the singleton as its proper type, I won't be able to see the full classes of its custom properties.

Steps to reproduce

In the main scene's script, main.gd:

class_name Main extends Node

var number: int = 7

func _enter_tree() -> void:
    Global.main = self
    Global2.main = self

func _ready() -> void:
    # Does not autofill number property, will also fail to infer type
    var num_a := Global.main.number
    
    # Does not autofill number property, but will properly infer type
    var num_b := Global2.main.number
    
    # Autofills number property, but casting fails when using a .tscn autoload
    var global_1 := Global as _Global
    var num_c := global_1.main.number
    
    # Autofills number property, and casting succeeds when using a .gd autoload
    var global_2 := Global2 as _Global2
    var num_d := global_2.main.number

In the first singleton script, global.gd, loaded as a .tscn:

class_name _Global extends Node

var main: Main

In the second singleton script, global_2.gd, loaded as a .gd:

class_name _Global2 extends Node

var main: Main

The autoload configuration:
image

Minimal reproduction project

TypeBug.zip

@AThousandShips
Copy link
Member

AThousandShips commented May 30, 2023

Creating an autoload from a .tscn file will cause the singleton node referenced by the global variable to be unconvertible to the type of the script specified after class_name, if it exists.

What error if any is thrown? Does this match or not the behaviour when having a node with the same script attached that is not autoload

@nazjun
Copy link
Author

nazjun commented May 30, 2023

Creating an autoload from a .tscn file will cause the singleton node referenced by the global variable to be unconvertible to the type of the script specified after class_name, if it exists.

What error if any is thrown? Does this match or not the behaviour when having a node with the same script attached that is not autoload

That line of code throws the Parser Error: Invalid cast. Cannot convert from "" to "_Global". error.

Creating a child node called NotGlobal with global.gd attached, then adding the following code does not throw any errors, but it also does not autocomplete the main property that is part of the _Global class, despite the static declaration, and treats it as a variable of type Node.

@onready var not_global: _Global = $NotGlobal

func _ready() -> void:
    var num_e = not_global.main.number

This matches the erroneous behavior described in #73638, where assigning the result of get_node (or its shorthand) to a statically typed variable will override the variable with the base type, instead of the one specified in the hint.

@HolonProduction
Copy link
Member

Related to #78454

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants