Pyrefly is a fast language server and type checker for Python.
Architecture:
As described in the README, our architecture follows 3 phases:
Here's an overview of some important directories:
Coding style: All code must be clean, documented and minimal. That means:
unreachable!("explanation") or .expect("explanation") — never _ => default, .unwrap_or_default(), or silent fallbacks. A type checker that silently produces wrong results is far worse than one that crashes with a clear message. Silent fallbacks hide bugs and confuse maintainers by making unreachable states look reachable.pyrefly_types crate before manually creating or destructuring a Type.Expr nodes are passed around and the number of times they are parsed. Generally, this means extracting semantic information as early as possible.use imports at the top of the file rather than using inline qualified paths (e.g., write use crate::foo::Bar; and then Bar, not crate::foo::Bar inline). The only exception is when there is a name collision between two imports, which is rare.Do not write a laundry list of implementation changes. Focus on:
A reader should be able to understand the intent and rationale from the commit message, without following all the code changes in details.
There are three possible development environments:
cargo is available. The buck and arc commands do not exist.buck is available. The cargo command may not be configured.buck and cargo are available.How to detect the environment: Check for the presence of a BUCK file in the project root. BUCK files are not exported to GitHub, so:
BUCK exists → internal checkout, buck and arc are availableBUCK does not exist → GitHub checkout, only cargo worksDo not assume git. This repo may be either a Git checkout or a Sapling (Mercurial-based) checkout. Before running any source-control commands, detect which VCS is in use:
.git exists at the repo root → Git. Use git commands..sl exists at the repo root → Sapling. Use sl commands (sl status, sl diff, sl commit, sl amend, etc.). Do not use git.You can check with: test -d "$(sl root 2>/dev/null)/.sl" && echo sapling || echo git
The internal (Meta) checkout always uses Sapling. The GitHub checkout uses Git.
buck test pyrefly:pyrefly_library -- <name of test> (from within the project folder)cargo test <name of test>Note: The heavyweight lsp_interaction tests live in a separate rust_unittest target for faster iteration. Run them with buck test pyrefly:pyrefly_lsp_interaction_tests -- <name of test>. Running buck test pyrefly:pyrefly triggers both test targets.
./test.py runs linters and tests. It is heavyweight, so only run it when you are confident the feature is complete.test.py auto-detects the build tool based on BUCK file presence. You can override this with --mode buck or --mode cargo.python3 test.py instead of ./test.py../test.py --no-test --no-conformance --no-jsonschemaarc autocargo to regenerate Cargo.toml files and validate changesAlways run formatting and linting before committing, updating a commit, or handing code off to a human for review: ./test.py --no-test --no-conformance --no-jsonschema
This applies whether you are committing autonomously or preparing code for a human to commit. Do not skip this step during human-in-the-loop iteration.
bug marker in testsThe testcase! macro supports a bug = "<description>" marker to indicate that a test captures undesirable behavior. Important points:
bug must pass. The marker documents that the behavior is wrong, not that the test itself should fail. Do not expect a bug-marked test to be a failing test.bug = "..." to explain what's wrong. This can be done to track issues or as part of a stack where a later diff fixes the bug.bug marker and update the test expectations to reflect the correct behavior.bug marker but update the message if it has become stale.bug message concise. For complicated bugs, add detailed explanations as comments inside the test body rather than making the marker message very long. If there is an associated Github issue, linking to it in a comment is often sufficient without paraphrasing the issue in the test.