Summary
When Pyrefly runs as a Type Server (pyrefly tsp), a typeServer/getComputedType request for a Node (a { uri, range } pair) returns null whenever the target file is not open in the server — even though the file is on disk, reachable, and analyzed as part of checking an open file. Opening the same file (via textDocument/didOpen) makes the identical request return a valid Type. Open and closed files should resolve to the same type.
Environment
- Reproduces on Pyrefly 1.0.0 and 1.2.0-dev.2 (latest dev), both started as
pyrefly tsp.
- Type Server Protocol
typeServer/getComputedType, arg = Node { uri, range } (zero-based, LSP-style character offsets).
Expected behavior
getComputedType is a position/node-based query keyed by (uri, range). It should return the computed type for a node in any file the server can analyze, regardless of whether that file is currently open in the editor.
Actual behavior
- Node in an open file → valid
Type.
- Same node in a file that is not open (but on disk and imported by an open file) →
null.
Minimal repro (protocol level)
-
initialize / initialized.
-
textDocument/didOpen for main.py only:
# main.py
import lib
x = lib.g()
# lib.py (on disk, NOT opened)
def g() -> None: ...
-
Send typeServer/getComputedType with arg.uri = lib.py and arg.range = the None return annotation of g. → Response: null.
-
Now textDocument/didOpen for lib.py and repeat step 3 → a valid Type is returned.
Real-world impact
This surfaced in Pylance + Pyrefly-over-TSP as microsoft/pylance-release#8122. Pylance never sends didOpen for bundled stdlib stubs, so every node inside Pyrefly's bundled builtins.pyi (e.g. the None return annotation of object.__init__) returns null from getComputedType. It is not typeshed-specific — any unopened user file behaves the same way (repro above).
Note / hypothesis
It looks like Pyrefly only retains position→node/type resolution for open documents, and returns null for (uri, range) lookups into background/closed files. Ideally the lookup should work for any analyzable file.
Summary
When Pyrefly runs as a Type Server (
pyrefly tsp), atypeServer/getComputedTyperequest for aNode(a{ uri, range }pair) returnsnullwhenever the target file is not open in the server — even though the file is on disk, reachable, and analyzed as part of checking an open file. Opening the same file (viatextDocument/didOpen) makes the identical request return a validType. Open and closed files should resolve to the same type.Environment
pyrefly tsp.typeServer/getComputedType, arg =Node { uri, range }(zero-based, LSP-style character offsets).Expected behavior
getComputedTypeis a position/node-based query keyed by(uri, range). It should return the computed type for a node in any file the server can analyze, regardless of whether that file is currently open in the editor.Actual behavior
Type.null.Minimal repro (protocol level)
initialize/initialized.textDocument/didOpenformain.pyonly:Send
typeServer/getComputedTypewitharg.uri=lib.pyandarg.range= theNonereturn annotation ofg. → Response:null.Now
textDocument/didOpenforlib.pyand repeat step 3 → a validTypeis returned.Real-world impact
This surfaced in Pylance + Pyrefly-over-TSP as microsoft/pylance-release#8122. Pylance never sends
didOpenfor bundled stdlib stubs, so every node inside Pyrefly's bundledbuiltins.pyi(e.g. theNonereturn annotation ofobject.__init__) returnsnullfromgetComputedType. It is not typeshed-specific — any unopened user file behaves the same way (repro above).Note / hypothesis
It looks like Pyrefly only retains position→node/type resolution for open documents, and returns
nullfor(uri, range)lookups into background/closed files. Ideally the lookup should work for any analyzable file.