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

Autocompletion breaks until the editor is restarted when a cyclic reference occurs #78074

Closed
Tracked by #80877
Tipyx opened this issue Jun 10, 2023 · 19 comments
Closed
Tracked by #80877

Comments

@Tipyx
Copy link

Tipyx commented Jun 10, 2023

Godot version

4.0.3 stable

System information

Windows 10

Issue description

Something is breaking the autocompletion when I used 2nd degree or more member of a variable.

Here's an exemple:

class_name MyClassA extends Node2D

func get_num():
	return 1

var classB : MyClassB

func _ready() -> void:
	Global.classA = self
	
	pass

And

class_name MyClassB extends Node2D

var classA : MyClassA

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	classA.classB.classA.get_num()
	pass

If you rename get_num to get_numb for exemple, the autocompletion in MyClassB will continue to show get_num (and CTRL+Click to it will refer to get.num), and I need to reload all the project because all future autocompletion will be outdated (like it stopped to update)

By the way, maybe it's related to #78003

I tested with the 4.1Beta, it still present

(First issue, I hope it's complete enough 😄)

Steps to reproduce

  • Download the sample project
  • Rename get_num to get_numb (or something else) in MyClassA
  • Try to autocomplete in MyClassB script after classA.classB.classA.

Minimal reproduction project

Issue.zip

@YuriSizov
Copy link
Contributor

Could you test the latest builds of Godot 4.1 (beta 3 at the time of writing) and compare?

@Tipyx
Copy link
Author

Tipyx commented Jun 28, 2023

Just tried with the Godot 4.1 RC 1, and it's still there

@ericmorand
Copy link

ericmorand commented Aug 30, 2023

I confirm that the issue is still there in Godot 4.1.1 stable.

Godot v4.1.1.stable - Windows 10.0.22621 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3060 (NVIDIA; 31.0.15.3713) - AMD Ryzen 5 5500 (12 Threads))

class_name Foo extends Node

func bar() -> int:
    return 5
class_name Mob extends Node

@onready var foo: Foo = get_node("Foo")

func _ready():
    foo.bar() // autocomplete succeeds
extends Node

@onready var mob: Mob = get_node("Mob")

func _ready():
    mob.foo.bar() // autocomplete fails

@hsandt
Copy link
Contributor

hsandt commented Sep 5, 2023

Did further testing, it looks like autocompletion works for members of the base class (e.g. Node2D), just not for custom members of the child class.

image

image

Similarly, Ctrl+click won't work at all.

I tried VS Code + GDScript plugin as a workaround, but it doesn't work either - I suspect because the language server asks Godot for autocompletion, but Godot has the bug so it propagates to VS Code.

@eddieataberk
Copy link

Having the same problem. Did anyone find a solution?

@HolonProduction
Copy link
Member

Looking at this I think it is not quite clear which issue we are talking about. The OP looks like a reload problem with Cyclic references.

I confirm that the issue is still there in Godot 4.1.1 stable.

Godot v4.1.1.stable - Windows 10.0.22621 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3060 (NVIDIA; 31.0.15.3713) - AMD Ryzen 5 5500 (12 Threads))

class_name Foo extends Node

func bar() -> int:
    return 5
class_name Mob extends Node

@onready var foo: Foo = get_node("Foo")

func _ready():
    foo.bar() // autocomplete succeeds
extends Node

@onready var mob: Mob = get_node("Mob")

func _ready():
    mob.foo.bar() // autocomplete fails

This is a different setup without cyclic references.
Please try substituting @onready var mob: Mob = get_node("Mob") with @onready var mob: Mob = get_node("Mob") as Mob. (Same for Foo). If this solves the problem you are actually looking at #73638.
If this does not solve your problem please provide a MRP with your setup.

@Calinou Calinou changed the title Autocompletion broke after 2nd degree member Autocompletion breaks until the editor is restarted when a cyclic reference occurs Mar 5, 2024
@DanielSnd
Copy link
Contributor

I think I'm running into this quite a bit, I'm running on a modified version of 4.3dev3 and was wondering if something I did in my modifications was causing the behavior but after looking at this and other similar issues it seems to be a known issue. I find myself restarting the editor a lot when coding. If I'm mostly in the same file it's fine, but the moment I need to edit a file that's referenced by a lot of others, I ran into the issue and have to restart.

Since the restart seems to fix it I guess a possible solution would be some sort of "clean and rebuild autocomplete cache" or something? Perhaps adding a button to the GDScript "File menu" similar to the existing "Soft Reload Tool Script" but a "Rebuild Autocompletion Cache" button? (When I was trying to find solutions that was one of the first things/places I looked)

@LO-0116
Copy link

LO-0116 commented Apr 16, 2024

I'm not 100% certain if cyclic reference per se causes the autocomplete break. I've had cyclic references in my v4.2.stable.official [46dc277] version and the autocomplete was working fine until I copy-pasted some code into the project.

The code causes an error, I immediately commented the whole thing but the autocomplete is irrevocably broken after that. It's really frustrating. This bug has been around since 4.0 iirc. (Probably unrelated: enums doesn't autocomplete if it's in a match block or if invoked from an instance instead of the class name.)

@LO-0116
Copy link

LO-0116 commented Apr 17, 2024

I think I'm running into this quite a bit, I'm running on a modified version of 4.3dev3 and was wondering if something I did in my modifications was causing the behavior but after looking at this and other similar issues it seems to be a known issue. I find myself restarting the editor a lot when coding. If I'm mostly in the same file it's fine, but the moment I need to edit a file that's referenced by a lot of others, I ran into the issue and have to restart.

Since the restart seems to fix it I guess a possible solution would be some sort of "clean and rebuild autocomplete cache" or something? Perhaps adding a button to the GDScript "File menu" similar to the existing "Soft Reload Tool Script" but a "Rebuild Autocompletion Cache" button? (When I was trying to find solutions that was one of the first things/places I looked)

I'm not sure if rebuilding the cache matters, I tried deleting and regenerating the .godot folder which contains all cache files but autocompletion remains broken

@dandeliondino
Copy link

dandeliondino commented Apr 22, 2024

Can also confirm this. It is highly reproducible with specific scripts and not others. And, like it was noted above, it does not seem solely related to the presence of cyclic references (there appears to be at least one other trigger required, perhaps a threshold number of references?), and deleting the .godot folder does not fix the problem.

It currently appears that there are three possible outcomes that may be different stages of same problem. As the project grows and the cross-referencing complexity increases, the scripts that are affected by (1) later become affected by (2) and then (3). Not being familiar with the core code, I wonder if perhaps these reflect different levels of recursion timeouts or other limitations leading to different fail states?

Edit: To clarify, the errors occur when adding a new member to the affected script, then attempting to reference that member from another script.

(1) Autocomplete fails, but no errors are reported in the editor or running the game.
(2) Autocomplete fails, and errors are reported in the script editor, but the game runs without error. After waiting some time, the errors in the script editor disappear.
(3) Autocomplete fails, errors are reported in the script editor, and the game fails to run due to errors. No amount of waiting resolves it. It requires a project reload.

This progression has been consistent for me across many projects. The first script affected is always the file that contains my global constants. It does not reference any other script, but many scripts reference it, and some of them contain cyclic references. The next scripts to become affected are usually superclasses with multiple subclasses and users (like a generic "Entity" script).

I start to see the process starting around the time the projects grow from about a dozen scripts to a few dozen scripts -- so they are still relatively small.

@akien-mga
Copy link
Member

CC @godotengine/gdscript
Given the last description, I think this might relate to other issues we've had where cached scripts seem to be out of sync with the files on disk and lead to weird errors.

@dandeliondino
Copy link

Thanks for looking into it! I want to clarify that I'm not 100% sure that it's the same problem as the original post, but it matches #80674, which was closed as being the same cause as this issue. And @LO-0116's observations seemed consistent with my experience that it has not been just cyclic references, but seems to require a second trigger.

@LO-0116
Copy link

LO-0116 commented Apr 29, 2024

Another thing I've noticed: static functions does not seem affected by broken auto-completes. That is to say, autocompletes that wouldn't work in the body of func will work in the body of static func and newly added static func will appear in other scripts whereas newly added func wouldn't

@HolonProduction
Copy link
Member

I tried to reproduce on master using the scripts that have no cyclic reference, and wasn't able to.
Using the mrp from the original issue which has cyclic references, I was able to.

When auto completion shows old names, outdated class types are set by the analyzer. This happens because the new parser created by code_completion is not part of the GDScriptCache, so when the analyzer encounters the same type which is currently completed on, it will use an old parser ref from the script, which might still have some old class types, depending on the idle parse time (I could only reproduce when being fast enough, and also needed some tries before it happened). Invalidating the gdscript cache for the current script when autocompleting could probably solve this issue.

On a different note, with #84266 I wasn't able to reproduce even with the cyclic references, I suppose it forces an update on the cache. This isn't the correct fix for this issue though.

Also the bug I found here, does not really fit all users who reported on having this problem in this thread. There have been some fixes with GDScript caching so I could imagine, that some more grave issues were already fixed by them. Did anyone with the problem give it a try with the last dev build?

@dandeliondino
Copy link

@HolonProduction So far, the issue I described appears not to be reproducible in 4.3-dev6! When I try to access newly-added variables from the previously affected scripts, autocomplete is populating immediately and there are no errors. Going back and forth with the same project in 4.3-dev5 still reproduces the errors I described.

@LO-0116
Copy link

LO-0116 commented May 28, 2024

Another thing I've noticed: static functions does not seem affected by broken auto-completes. That is to say, autocompletes that wouldn't work in the body of func will work in the body of static func and newly added static func will appear in other scripts whereas newly added func wouldn't

Update: this also breaks after adding enough things to the project. I get the feeling now that the autocomplete breaking is not a matter of quality but a matter of quantity. i.e.: when there are too many things to autocomplete, the autocompletion deteriorates, starting with "vulnerable" things like classes with cyclic references then eventually affecting even less vulnerable things like static functions

@DanielSnd
Copy link
Contributor

I feel like now I have a new version of this issue, which now spawns a new error.

In general, I feel like the issue has been mostly solved, the autocompletion seems to be way more resilient to code changes and in places where they would often break before it stays working just fine in 4.3beta1.

But every once in a while I noticed I would get errors like this spammed in the output:

USER ERROR: Parser bug: Mismatched external parser.

The error message doesn't tell me much, so I went digging around. The error was coming from this method in gdscript_analyzer.cpp:

void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, int p_index, const GDScriptParser::Node *p_source) {
		ERR_FAIL_COND_MSG(!parser_ref->get_parser()->has_class(p_class), R"(Parser bug: Mismatched external parser.)");

So I added these before it to catch some more information:

if (!parser_ref->get_parser()->has_class(p_class)) {
			if (p_class == nullptr) {
				push_error(vformat(R"(Parser did not have class NULLPTR script "%s" member "%s")",script_path,member.get_name()),p_source);
			} else {
				push_error(vformat(R"(Parser did not have class %s script "%s" member "%s")",p_class->get_global_name(), script_path,member.get_name()),p_source);
			}
		}

I think it would be good in general to include some more information in that error.

It took a while to happen in the editor again, but in the meantime it popped up in a build for me.

USER ERROR: Parser bug: Mismatched external parser.
   at: GDScriptAnalyzer::resolve_class_member (modules\gdscript\gdscript_analyzer.cpp:916)
USER SCRIPT ERROR: Parse Error: Parser did not have class Skill script "res://resources/skill.gd" member "found_button"
   at: GDScript::reload (res://resources/skill.gd:100)
USER SCRIPT ERROR: Parse Error: Parser did not have class Skill script "res://resources/skill.gd" member "relevant_button_ui"
   at: GDScript::reload (res://resources/skill.gd:103)

The code in question was this, which was in the Skill class, referencing a member in the Skill class itself, but iterating over an Array[Skill] that was in another class:

	for skill in p.current_skills:
		if skill.found_button:
				continue
		skill.button_desired = "skill_"+str(non_ult_non_mov_skill_count+1)
		skill.relevant_button_ui.texture = App.skill_glyphs[non_ult_non_mov_skill_count]
			non_ult_non_mov_skill_count+= 1
		skill.found_button=true

That error was present every time I built, that one was pretty reproducible. I tried building an MRP trying to do a similar thing but I couldn't get an MRP to reproduce the same error.

I noticed I had not typecasted skill in the for loop. Typecasting it instantly made the error go away on builds.

I'm not sure why the error on builds happened, but this script used to be fine when I was using a previous 4.3dev so I'm assuming some sort of regression.

Now back to the editor, took a while but the same USER ERROR: Parser bug: Mismatched external parser. came back.

image

In this case the script (the one in game_syncer) was valid, then I edited it became invalid, I fixed whatever error made it invalid but the fix is not taken into account in other scripts that reference it maybe? Restarting the editor makes the error go away and the parser recognizes the member just fine. This made me think that it's related to this issue with cyclic reference.

Should I start a new issue or is this still related to the same issue? So far it seems to happen way more rarely than the original issue, and I can't seem to make an MRP for it as it happens semi-randomly while working. I'm also running a custom build with custom modules so I can't 100% say it isn't related to my own custom code.

@HolonProduction
Copy link
Member

HolonProduction commented Jul 12, 2024

@godotengine/bugsquad Can we please close this issue?

As per the comment of @dandeliondino the original issue seems to be not a problem anymore. The other problems/issues mentioned in this thread require different conditions than the original report and should be their own issue with an MRP. The way it currently is, it's just not possible to reproduce, work on or keep track of any of them.

@DanielSnd please create a new issue including an MRP if this issue is still present with 4.3.beta3. Same to all other users who encountered loosely related problems. (This issue is about cyclic dependencies and outdated members. Anything else belongs in an own report.)

@adamscott
Copy link
Member

Closing the issue as the MRP behaves as it should on v4.3.beta.custom_build [26d1577] (latest master).

@dalexeev dalexeev added this to the 4.3 milestone Jul 12, 2024
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