astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.
https://docs.astral.sh/ruff
MIT License
31.93k stars 1.07k forks source link

[red-knot] circular references in class definitions panic #13792

Open rtpg opened 2 hours ago

rtpg commented 2 hours ago
class C(list[C]): ...

the above code causes red_knot to panic, due to something a bit subtle:

This leads to C being infered of type Unknown thanks to infer_definition_types_cycle_recover, which is fine and great... but due to something I don't quite understand, the result of infer_definition_types_cycle_recover ends up being the final definition of infer_definition_types(C).

As a result we lose the inference on list! So later linting code that traverses the AST tries to look up the type of the list expression and blows up.

My understanding here is that the queries are like:

infer_definition_types(C) -> infer_definition_types(C)
--------------------------------------------------------
infer_definition_types(C) -> [C: Unknown]
--------------------------------------------------------
[C: ClassType (base: Unknown), expressions: {list} ]

but that future queries to the DB for infer_defintion_types(C) ends up returning [C: Unknown]. I have been reading the docs on salsa cycling a bit on this point to try and decipher what is going on here but maybe somebody else would have a better understanding of what can be done here.

MichaReiser commented 2 hours ago

@carljm's working on fixpoint iteration that will allow cyclic dependencies

rtpg commented 1 hour ago

Alright, good to know! I had this intuition that I didn't need general fixed point iteration (just not caching the cycle recovery result for definitions), but trying to db.report_untracked_read my way out of this got me nowhere.

Will studiously wait on this one for the adults to show up with the principled solution when the time is right.