catch-up: merge astral-sh/ruff main downstream into fork (baseline, not for merge) - #100
Conversation
…l-sh#27431) ## Summary Preserve callable return-type constraints when matching `Callable[..., T]` against callbacks with `*args: object` and `**kwargs: object`. fixes: astral-sh/ty#4151 fixes: astral-sh/ty#4169 ## Test plan Add a focused regression for return-type inference through object-variadic callbacks. Verified the original issue reproduction now infers `ChildClass` for the decorated method result.
## Summary Preserve return-type inference for `Top[Callable[..., T]]`. Follow-up to astral-sh#27431 (comment). ## Test plan Cover return-type inference for an ordinary callback accepted as a top callable.
## Summary Bump both ty ecosystem workflows to astral-sh/ecosystem-analyzer#143, which includes hauntsaninja/mypy_primer#257, which fixes `attrs` and `Bokeh`.
## Summary Top-materialize th gradual `DataclassInstance` protocol in the `TypeIs` return type of `is_dataclass`, so that we can recognize dataclass instances as being a subtype of that return type. Fixes astral-sh/ty#4149. ## Ecosystem impact Looks good! ## Test plan Updated and added mdtests.
…7458) ## Summary Reject unrecognized `dataclass_transform` parameters based on this paragraph in the [spec](https://typing.python.org/en/latest/spec/dataclasses.html#dataclass-transform-parameters) (emphasis mine): > kwargs allows arbitrary additional keyword args to be passed to dataclass_transform. This gives type checkers the freedom to support experimental parameters without needing to wait for changes in typing.py. **Type checkers should report errors for any unrecognized parameters.** Since we currently don't do any experiments with unofficial parameters to `dataclass_transform`, we can just remove `**kwargs`. Fixes astral-sh/ty#4170. ## Test plan New Markdown tests.
## Summary OR-pattern alternatives can bind the same names but "execute" mutually exclusively. The semantic index previously visited alternatives as consecutive assignments, so later captures shadowed earlier captures and caused the language server to incorrectly report those earlier bindings as unused. Visit each capture-bearing alternative from the same incoming flow state and merge the resulting bindings. Preserve the existing fast path for OR patterns that do not bind names. Closes astral-sh/ty#4163. ## Test plan - Used captures across multiple OR-pattern alternatives and captured names. - Nested OR-pattern captures referenced only by a match guard. - Genuinely unused alternative captures, earlier shadowed assignments, and captures in separate match cases.
…stral-sh#27340) ## Summary Constructing a generic class from one of its own type variables currently loses that type variable and produces `C[Unknown]`. We now freshen the constructor-specific generic context while preserving the source-level return template, so `C(value)` within `C[T]` retains `C[T]`. We also keep bound constructor receivers and downstream `__init__` bindings on the same fresh occurrence, and distinguish that occurrence from outer type variables during inference. Closes astral-sh/ty#4132. Closes astral-sh/ty#3963.
) ## Summary We now exclude private type variables, parameter specifications, type-variable tuples, aliases, and `@type_check_only` definitions from completions, even though those names can be explicitly imported in typing-only contexts: ```python from typing import TYPE_CHECKING if TYPE_CHECKING: from package import _Alias, _T ``` This PR makes those definitions consistent with existing `@type_check_only` completion behavior: retain them as explicit import and attribute completions, mark them as typing-only, and rank them below runtime values.
…sh#27453) ## Summary On Python 3.14, deferred annotations allow a function to reference a `TypeVar` declared after calls to that function: ```python class C: ... def f(a: T): ... if f(): pass if f(): sum() else: sum() from typing import TypeVar T = TypeVar("T", default=C) ``` Previously, resolving `T`'s default during generic specialization re-entered the same Salsa query through reachability analysis, causing a dependency-cycle panic. We now initialize specialization cycle recovery with unknown type arguments, allowing Salsa to complete the surrounding inference without evaluating the default recursively. Once inference stabilizes, the actual default remains `C` and we report the expected argument and overload diagnostics. Closes astral-sh/ty#4174.
…tral-sh#27459) This PR moves the benchmarks that exercise our constraint set implementation into their own file. This is a refactoring pulled out of astral-sh#27337. The source file is included in Codspeed's benchmark ID, so moving them like this disconnects these benchmarks from their history. Doing the move in a separate PR means that astral-sh#27337 will at least show an accurate delta for the existing benchmarks relative to `main`.
…res (astral-sh#27436) ## Summary Prior to this change, constructing a bare generic `TypedDict` discarded the constraints provided by its fields: ```py from typing import TypedDict class Box[T](TypedDict): value: T reveal_type(Box(value=1)) # Box[Unknown] ``` This PR makes the synthesized `TypedDict.__init__` generic, so direct keyword calls use the same overload matching, contextual inference, and constraint solver as other generic constructors. For now, we only support direct keyword calls, as in: ```py class Pair[T](TypedDict): first: T second: T reveal_type(Box(value=1)) # Box[int] reveal_type(Pair(first=1, second="x")) # Pair[int | str] ``` Positional mappings and dictionary unpacking are deferred... their field constraints can't yet be propagated through ordinary constructor binding without losing key-specific information or mishandling overwrites: ```py reveal_type(Box({"value": 1})) # Box[Unknown] reveal_type(Box(**{"value": 1})) # Box[Unknown] ``` Nested generic `TypedDict` fields are also deferred until their constraints can be propagated soundly. Recursive construction remains valid, but retains its existing gradual specialization: ```py from typing import NotRequired class Node[T](TypedDict): value: NotRequired[T] child: NotRequired["Node[T]"] reveal_type(Node(child=Node(value=1))) # Node[Unknown] ``` Closes astral-sh/ty#4134.
astral-sh#27463) <!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> This renames an internal helper function to be slightly more descriptive of the predicate it encapsulates. ## Test Plan This is a simple rename that relies on existing test coverage. <!-- How was it tested? -->
…l-sh#27442) ## Summary Generic method decorators and descriptor constructors could erase enclosing class type parameters when callable-signature comparison expanded implicit `Self` bounds and existentially quantified the entire inferable set. This caused decorated methods to return `Unknown` and produced false-positive diagnostics for generic `cached_property` methods. Preserve enclosing class variables during lazy comparisons while retaining expanded inference for eager unbound-method comparisons, including inside generic higher-order calls. Generic cached-property protocol members now expose their correctly specialized readable and writable types. Fixes astral-sh/ty#4153. Fixes astral-sh/ty#3256. ## Test plan - Added mdtests for PEP 695 and legacy generic method decorators, including nested `list[T]` return types. - Added mdtests for generic `cached_property` methods with direct and union return types, and updated generic protocol descriptor specialization coverage. - Added mdtests for generic higher-order functions receiving unbound generic methods, including `functools.reduce(set.union, ...)`. - Added a constraint-level regression while preserving existing unbound-method assignability coverage.
…-sh#27460) ## Summary Previously, we only recovered a generic constructor's specialization from an overload that passed argument validation. If validation failed, we discarded any type arguments the binding had already inferred, allowing the class's internal type variables to escape into the constructed value. See here, where we emit two diagnostics on `consumer: Consumer[Animal] = Consumer(accepts_dog)`: ```py from collections.abc import Callable class Animal: ... class Dog(Animal): ... class Consumer[T]: def __init__(self, callback: Callable[[T], None]) -> None: self.callback = callback def accepts_dog(value: Dog) -> None: ... # error: [invalid-assignment] Object of type `Consumer[T@Consumer]` is not assignable to `Consumer[Animal]` # error: [invalid-argument-type] Argument to `Consumer.__init__` is incorrect: Expected `(Animal, /) -> None`, found `def accepts_dog(value: Dog) -> None` consumer: Consumer[Animal] = Consumer(accepts_dog) ``` The callback error is correct: `accepts_dog` cannot handle every `Animal`. But the constructor binding had already established `T = Animal` from its surrounding context. Discarding that specialization returned `Consumer[T@Consumer]` and produced a second, misleading assignment error. We now preserve the specialization already established by constructor binding, even when argument validation fails, so only the callback error remains. The net effect is that we show fewer redundant errors and fewer cascading errors.
## Summary Teach the `SymbolVisitor` to recognize names introduced by structural pattern matching. This handles: - capture and `as` patterns; - sequence and starred patterns; - mapping patterns, including `**rest`; - positional and keyword class patterns; - nested patterns and `|` alternatives; - module-level bindings as variables or constants; - class-level bindings as fields. Function-local bindings remain excluded, consistently with regular assignments. Pattern bindings, guards, and case bodies retain source-order traversal. Addresses the `case bar:` item in astral-sh/ty#1771. > [!NOTE] > This draft has been realigned on top of astral-sh#27256, which now provides the generic Store-context handling. This PR now contains only the match-pattern binding support. ## Test Plan - `cargo test -p ty_ide` - `cargo clippy -p ty_ide --all-targets --all-features -- -D warnings` - `uv run --only-group dev --locked prek run --files crates/ty_ide/src/symbols.rs crates/ty_ide/src/document_symbols.rs` --------- Co-authored-by: Lérè <contact@lrbr.dev>
## Summary Previously when we reported the intersection type that a constructor call tried to call, we synthesized an intersection of the constructor methods (e.g. `__init__`, `__new__`, or metaclass `__call__`). Since these are often bound methods, which are disjoint from other bound methods, this synthesized intersection might resolve to `Never`, leading to a confusing sub-diagnostic claiming that we had tried to call the intersection `Never`. Instead, preserve each union element's called type while constructing and transforming bindings, so intersection diagnostics report the original class types instead of collapsing constructor method signature intersections into `Never`. ## Test plan - Add snapshot-backed mdtests for standalone constructor intersections and constructor intersections nested inside unions. - Cover excluded types in layered intersection diagnostics and single-callable union variants.
…h#27449) ## Summary This PR validates `type[T]` against `T`'s upper-bound, but leaves bare `type` permissive: ```py from collections.abc import Callable def permissive(cls: type) -> None: cls(1) # still accepted def unbounded[T](cls: type[T]) -> T: zero_argument: Callable[[], T] = cls one_argument: Callable[[int], T] = cls # error: [invalid-assignment] return cls(1) # error: [too-many-positional-arguments] def object_bound[T: object](cls: type[T]) -> T: return cls(1) # error: [too-many-positional-arguments] ``` I believe this is both consistent with the [constructor typing specification](https://typing.python.org/en/latest/spec/constructors.html#constructor-calls-for-type-t) and gets us passing the relevant conformance tests. The background is that in astral-sh#24357, we brought constructor handling much closer to the typing specification by respecting `__new__` and metaclass `__call__` return types, but `constructors_call_type.py` still had one false negative (calling an unbounded `type[T]` with arguments). We then put up astral-sh#23514 which addressed that case by overriding the permissive typeshed signature for `type.__call__`, making bare `type`, `type[object]`, and unbounded `type[T]` all use `object`'s zero-argument constructor. That created substantial ecosystem fallout and added conformance false-positives. @carljm suggested that, if we eventually want stricter `type[object]`, we should instead distinguish it from bare `type` instead of globally replacing `type.__call__`.
…stral-sh#27493) ## Summary In astral-sh#27449, we start treating calls to `type[object]` strictly (using `object.__init__` rather than the overly forgiving `type.__call__`). This also means that `type[T] & type[SomeType]` intersections (which can easily arise with a parameter `cls: type[T]` which is then narrowed via `issubclass(cls, SomeType)`) start validating the `type[T]` portion against `object.__init__` (assuming `T` has no upper bound besides `object`). That means if the call to `type[SomeType]` fails, we now get confusing double diagnostics also complaining about the failed call to `object.__init__`. This PR resolves that problem separately in a general way: if we have an intersection `type[T] & type[SomeClass]`, where `SomeClass` is a subclass of the upper bound of `T`, we don't try calling both constructors; we just try the constructor of `SomeClass`. (But we preserve the full intersection as receiver, so that the result of the call will still be `T & SomeClass`, not just `SomeClass`.) Since all classes are subclasses of `object`, this means we don't try calling `object.__init__` or emit errors about it when they are redundant and confusing in an intersection with some more specific `type[...]`. (This is only relevant to intersections with `type[T]` where `T` is a typevar, since a normal `type[Base] & type[Child]` intersection would immediately simplify to `type[Child]`. That simplification doesn't occur with a typevar, since we need to preserve the typevar identity; it may actually represent a narrower type, not its upper bound.) - Resolve constructor calls on narrowed `type[T] & type[Child]` intersections using the applicable subclass constructor instead of treating the type-variable bound as an independent alternative. - Preserve the precise `T & Child` result, report only subclass-constructor argument errors, and retain specialized generic constructors, built-in behavior, independent metaclass callables, and explicit `__new__` / metaclass `__call__` return types. ## Test plan - Added constructor mdtests for `issubclass`-narrowed bounded, constrained, and unbounded type variables; valid return types; rejected arguments; and deduplicated diagnostics. - Covered explicitly specialized generic constructors, literal-preserving built-in constructors, `Self` returns, non-instance `__new__` and metaclass `__call__` returns, and intersections with independent metaclass callables. Ecosystem changes are both correct/improvements.
…tral-sh#27790) ## Summary Move implicit-attribute inference out of the large static-class implementation and into `types/class/implicit_attributes.rs`.
…al-sh#26693) ## Summary Preserve source ranges for PEP 723 script metadata by building a compact source map during extraction and applying it when deserializing ranged values. Closes astral-sh/ty#4180
<!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary Adds explicit 7d cooldowns to all of our PEP 723 scripts, as well as similar cooldowns via `.npmrc`. <!-- What's the purpose of the change? What does it do, and why? --> ## Test Plan NFC. <!-- How was it tested? --> --- <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
<!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary Addresses all `uv audit` findings. <!-- What's the purpose of the change? What does it do, and why? --> ## Test Plan NFC. <!-- How was it tested? --> --- <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
Signed-off-by: William Woodruff <william@yossarian.net>
…rsive queries (astral-sh#27737) ## Summary This fixes a "too many iterations" panic I saw when fixing astral-sh/ty#4246. This panic reproduces on main already with a slightly different example, so fix it first here. Irrelevant quantified-away constraints can pollute a source-ordering sidecar and cause fixpoint to never converge. - Drop quantified-away constraints from persisted source ordering when their complete support is unrelated to the remaining live constraint set. This prevents fresh type variables from keeping recursive Salsa queries from reaching a fixed point. - Preserve related quantified constraints and conservatively retain entries whenever either support is incomplete. - Stop collecting type-variable declaration bounds, value constraints, and defaults as constraint support, so unrelated eager metadata does not add dependencies and lazy metadata does not incorrectly mark support incomplete. Related to astral-sh/ty#4246 and astral-sh#27732. ## Test plan - Add an overloaded generic-protocol classmethod mdtest that reproduces `too many cycle iterations` on main and verifies both receiver-bound overload signatures. - Add separate protocol receiver-binding mdtests for a bounded legacy type variable and a defaulted PEP 695 method type variable. - Cover removal of unrelated quantified constraints and preservation of ordering for related quantified constraints with focused constraint-set unit tests. - Cover eager type-variable defaults and lazy declaration bounds, value constraints, and defaults while preserving type variables actually present in structural constraint bounds.
…#27786) A nested class or comprehension inside a function could infer only the conditionally reassigned value of a `global`, dropping its existing module-level value. This let ty accept code that could fail at runtime, and could cause false-positive `possibly-unresolved-reference` errors. Resolve forwarded global snapshots against real module-level bindings and declarations before falling back to implicit globals or builtins. Exclude synthetic bindings from nested `global` assignments so existing implicit-global and builtin behavior is preserved. Closes astral-sh/ty#4273. ## Test plan Added scope mdtests covering: - A nested class reading a global with an existing module-level binding after conditional reassignment. - A nested class reading a global that has only a module-level type declaration. - An eager comprehension reading a conditionally reassigned global. Existing neighboring mdtests also cover fallback to implicit globals and builtins.
We currently ignore concrete upper bounds when inferring a gradual
solution. We should instead be intersecting the gradual type with its
upper bound, e.g.,
```py
from typing import Any, Callable
def infer[T](lower: T, upper: Callable[[T], None]) -> T:
return lower
def _(x: Any, upper: Callable[[int], None]):
reveal_type(infer(x, upper)) # revealed: int & Any
```
…sh#27732) ## What was the problem? Checking an expression such as `pd.Series([1.0]) + np.array([1.0])` could hang indefinitely. The Series already determines one of the addition method's type variables, but ty tried to infer it together with the remaining arguments. That left too many possibilities to consider across NumPy's many operator overloads. ## How does this fix it? When a method explicitly annotates `self` or `cls`, first determine any method type variables fixed by that object. Use those known types when checking the remaining arguments and describing the bound method, while leaving unrelated variables available for normal argument inference. Only do this extra work when the variable also appears in another parameter or the return type. Variables used only in the receiver, variables belonging to the class, and `typing.Self` cannot help with argument checking. Skipping them avoids unnecessary work and preserves performance on `DateType` and `hydra-zen`. Type aliases are handled without expanding their definitions. Fixes astral-sh/ty#4246. ## Test plan - Cover a generic method where the receiver determines one type variable and another argument determines a separate variable. - Cover type aliases in receiver annotations, return types, and other parameters. - Cover type variables used only in the receiver, which should remain unspecialized. - Verify pandas Series addition and multiplication with NumPy arrays, with no performance regressions on `DateType` or `hydra-zen`.
…tral-sh#27703) ## Summary When analyzing a `try` block, we record which bindings an exception handler could see before each potentially raising operation. In a large function, copying and later merging these snapshots can be expensive. We already reuse checkpoints for consecutive calls when nothing relevant changes. However, harmless control flow can defeat that optimization: ```python def example(value: str, flag: bool) -> None: try: value.upper() if flag is True: pass value.upper() except Exception: pass ``` The `if` introduces branches, but after they rejoin, the second call exposes the same bindings to the handler. Previously, restoring or merging a branch always advanced the checkpoint's control-flow revision, so we retained another snapshot. We now recognize equivalent paths and reuse the checkpoint. Equivalent control flow does not necessarily mean equivalent bindings: nested exception handlers can merge paths with different possible values. To preserve all of those values, we track a restorable identity for the visible bindings as well as reachability, giving distinct merged states a fresh identity. We also preserve the call history needed to handle caught `NoReturn` calls correctly. If the reachability graph reaches its size limit, we fall back to conservative deduplication rather than retaining a snapshot for every subsequent call. Two supporting changes avoid redundant work when combining a reachability condition with itself and keep the larger flow snapshots out of the common recursive expression-visitor stack frame. This is complementary to astral-sh#27787: that change makes evaluating narrowing and reachability histories cheaper, while this change avoids constructing redundant exception-state snapshots. ## Performance On a synthetic workload with 800 locals and 800 calls separated by equivalent `if` branches, this reduces CPU time by about 26% and peak memory by 59%. The ordinary-call control and the suppression-heavy workload are essentially unchanged: | Workload | CPU, before → after | Peak RSS, before → after | | --- | ---: | ---: | | Plain repeated calls | 148 → 148 ms | 123.4 → 123.3 MiB | | Calls separated by equivalent `if` branches | 268 → 199 ms | 102.5 → 42.1 MiB | | Conditional assignments under suppression | 819 → 816 ms | 111.2 → 109.9 MiB |
On Python 3.12, aliases declared with `type Alias = int` are instances of `typing.TypeAliasType`, but ty currently infers them as instances of `typing_extensions.TypeAliasType` because both classes share a `KnownClass` variant that resolves to the backport. - Distinguish the standard-library and backport `TypeAliasType` classes with separate `KnownClass` variants. - Generalize `TypedDictModule` into a shared `TypingModule` enum and retain the actual constructor origin on manually created aliases through specialization and materialization. - Update alias construction, runtime-class fallback, TypedDict handling, and IDE argument classification to use the correct module. - Cover statement-defined aliases and both direct constructors on Python 3.12, and update `__type_params__` inference to reflect the standard-library class. The fact that we fail to model this precisely right now appears to cause a surprising number of ecosystem diagnostics on bokeh.
Lazy protocol checks currently replace `type[T]` and `type[Any]` with plain `type`. This loses the class object's interface before generic inference can use it. For example, collecting an iterable class together with an empty fallback can lose `Self` and infer `Unknown` instead. Allow lazy assignability to use the same structural protocol check as eager assignability. Strict subtyping keeps its existing behavior. This is a prerequisite for astral-sh#27812 and is related to astral-sh/ty#4291. ## Test plan - Add a public mdtest using a generic metaclass iterator and a classmethod that collects `frozenset[Self]` through an empty fallback. - Cover a gradual class object combined with a concrete iterable, ensuring the concrete element type still contributes to inference.
An annotated assignment could lose its declared type in an exception handler, when the path to the exception handler is through an exception evaluating its right-hand side. Assignments in the handler were then inferred without that type context, so a fallback assignment could acquire an incompatible value type, without the benefit of type context from the declared type. This is arguably "expected behavior" in our flow-sensitive declared-types model, but intuitively it feels like the declaration should "take effect" before the RHS "executes". Modeling it that way requires a bit of new machinery in the use-def map to allow splitting the declaration and binding from a single assignment in control flow, but it's not too bad and even allows some simplifications. Record the declaration before visiting the annotation and right-hand side, then record the value binding only after the right-hand side completes. The two control-flow entries retain their execution order, but only the binding participates in usage analysis. Keeping usage state in those entries also removes the parallel usage vector. This preserves ty's existing exception-point model. Fixes astral-sh/ty#4293. ## Test plan - Exception-flow mdtests cover contextual dictionary inference, incompatible fallback assignments, previous or unbound values, reannotations, declarations after an earlier exception checkpoint, and assignments made inside the right-hand side. - Unused-binding tests cover annotated loop-carried values, shadowed annotated bindings, and later bindings captured by closures.
…to 2026-08-18 Upstream catch-up merge: brings this fork's history (merge-base 8c930f5) forward by 1512 upstream commits, alongside the fork's own 313 commits since that point. This is kept as a separate integration branch (claude/upstream-catchup-2026-08-18) and is not merged into the fork's main branch. Two upstream features arrive as part of this catch-up, no separate porting needed: - RUF105 (invalid rule code in `noqa` comment) - Human-readable rule names in selectors (`is_human_readable_names_enabled`, `Rule::from_name`, `UnresolvedRuleSelector::resolve`) Real conflicts (37 files overlapped fork vs. upstream changes; most were either the fork's own mechanical clippy-1.97 sweep colliding with upstream's own independent mechanical simplifications at the same lines, or a genuine union merge): - AGENTS.md: took upstream's full rewritten file, re-inserted the fork's SPO/transcode-crate paragraph after the intro. - Cargo.toml: union merge — adopted upstream's per-crate `version = "0.0.9"` style workspace.dependencies entries, kept the fork-only path deps (ruff_cpp_codegen, ruff_spo_triplet), kept the fork's `exclude = ["crates/ruff_r2il"]` and the local lsp-types vendor patch (now inert since upstream moved lsp-types off its git dependency onto a published crate, but harmless — cargo just warns, doesn't fail). - Cargo.lock: regenerated via `cargo generate-lockfile` from the merged Cargo.toml rather than hand-resolved. - crates/ruff/src/lib.rs, crates/ruff_linter/.../sort_dunder_slots.rs, crates/ruff_server/tests/e2e/main.rs, crates/ty_server/tests/e2e/main.rs, crates/ty_python_semantic/src/types/narrow.rs: took upstream's side — fork's only change at each conflict site was a mechanical clippy-1.97 `question_mark`/style fix, semantically identical to upstream's own independent simplification. - crates/ty_python_semantic/src/types/protocol_class.rs: took upstream's side — fork's only change nearby was stripping redundant `&` borrows in `format_args!`; upstream had independently restructured the whole `display` method for unrelated reasons. - crates/ruff_python_formatter/src/range.rs: took upstream's side — verified the fork's `#[expect(clippy::question_mark, ...)]` preserved style was semantically identical to upstream's `?`-based rewrite (both already returned None in the missing-indentation case). - crates/ruff_annotate_snippets/src/renderer/display_list.rs: modify/delete conflict; upstream deleted the file as part of vendoring a newer annotate-snippets (astral-sh#27033, restructured into render.rs etc.); the fork's only change was a mechanical clippy fix, so followed upstream's deletion. - .github/workflows/ci.yaml, .pre-commit-config.yaml, python/ruff-ecosystem/ruff_ecosystem/defaults.py, scripts/check_ecosystem.py: auto-merged cleanly by git with no conflict markers; verified by hand that the fork's deliberate additions (the ruff_cpp_spo Windows libclang-crash exclusion in ci.yaml; the vendor/.claude/dto_check golden exclusions plus the mangled-fixer-hook-data comment in .pre-commit-config.yaml) survived intact and correctly grafted onto upstream's current file structure. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_708dc700-c08c-49fd-8353-e4cf093900cd) |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Upstream (pulled in by this catch-up merge) no longer depends on
lsp-types via git at all — it now uses the published gen-lsp-types
crate (see the `lsp-types = { package = "gen-lsp-types", ... }`
alias already in Cargo.toml). The fork's `[patch]` block still
pointed cargo at a git URL nothing depends on anymore, redirected to
a gitignored, never-committed `vendor/lsp-types/` path.
Locally this was silent ("unused patch" warning). In the Docker
build (a fresh container with no locally-regenerated vendor dir) it
was fatal: cargo still probes every `[patch]` source during manifest
resolution regardless of whether anything in the graph uses it, so
`cargo zigbuild` failed trying to read a Cargo.toml that was never
part of the repo.
Removed the patch block, the vendor/ gitignore entry, and the
dev-unblock-lsp-types.sh script that generated it (nothing else in
the tree references the old git source — checked). Cargo.lock
regenerated; only the dead git-source lock entry (4 lines) dropped,
gen-lsp-types resolves unchanged.
Pre-existing lint debt, exposed by real CI running full-workspace clippy on this catch-up branch for the first time (confirmed via `git diff` that the surrounding merge touched zero files in this crate — this is not a merge-introduced regression). The loop iterates a HashMap<String, (String, String)> and checks each entry independently against only its own value plus a running count (`parentless_checked`); no assertion in the body depends on which order entries are visited. Per AGENTS.md's own guidance, #[expect(...)] with a reason beats a blanket #[allow] here since this is a real, order-independent iteration rather than dead code.
Real CI on the catch-up PR (#100) surfaced two findings on the Windows ruff_cpp_spo exclusion added in #99, neither of which the local prek gate could catch at the time (zizmor's own audit needs outbound GitHub API access this sandbox's proxy denies — confirmed 403, same failure mode either way): - zizmor: medium-severity template-injection finding — interpolating `${{ matrix.platform }}` directly into a `run:` shell block substitutes before bash ever sees the script, so a value containing shell metacharacters could break out of the string context. Has a documented auto-fix: pass through `env:` instead. - actionlint/shellcheck SC2193 on the same line, which the env-var form also resolves (shellcheck sees a normal `"$VAR" == pattern` comparison rather than a literal it can statically reason wrongly about). matrix.platform itself is not attacker-controlled here (a static 2-value list gated on `github.repository`), but the fix is correct regardless of that — env-var passing is the general mitigation for this class of finding, not a per-instance judgment call.
Real CI's prek gate (a required check) surfaced this consistently on this catch-up branch: AGENTS.md uses asterisk emphasis everywhere except this one line, which markdownlint-fix flags and rewrites. Confirmed genuine before accepting — grep shows it's the sole underscore-emphasis line in an otherwise asterisk-emphasis file, so this fixes a real (harmless, upstream-inherited) inconsistency rather than introducing fork drift from upstream's style.
Real CI on the catch-up PR surfaced this on both docker-build matrix
legs: `ghcr.io/${{ github.repository_owner }}/ruff` resolves to
`ghcr.io/AdaWorldAPI/ruff` on this fork, and OCI registries reject
any mixed-case repository name outright ("failed to parse ref ...:
repository name ... must be lowercase"). Upstream never hits this —
`astral-sh` is already all-lowercase.
The workflow-level `env:` can't lowercase inline (no `lower()` in
GitHub Actions expression syntax), so each of the four jobs
(docker-build / docker-publish / docker-publish-extra /
docker-republish) gets a first step that recomputes RUFF_BASE_IMG via
bash's `${VAR,,}` into $GITHUB_ENV, overriding the workflow-level
fallback for the rest of that job before any step actually
builds/tags/pushes an image reference.
Only docker-build is exercised by this PR (the other three jobs gate
on `inputs.plan`, which is unset outside an actual release run via
workflow_call) — fixed all four anyway since a real release attempt
on this fork would hit the identical failure otherwise.
Root cause of the two stuck CI runs on this catch-up PR (both attempts hung with `PGO` queued 40+ minutes, no runner ever claimed it, and several other required jobs got cancelled alongside it before the run could reach a clean terminal state for a failed-jobs rerun): `pgo`'s `runs-on: depot-ubuntu-24.04-8` was hardcoded with no fork fallback — unique among this file's other three bare `depot-*` jobs, which all correctly gate their own `if:` on `github.repository == 'astral-sh/ruff'` so they're skipped entirely on a fork (confirmed via their own comments/conditions). `pgo`'s `if:` only checks `determine_changes.outputs.release`, so it actually attempts to run on this fork — and `depot-*` are Depot.dev custom runners registered only for the upstream org, so nothing can ever claim that label here. Applied the same `github.repository == 'astral-sh/ruff' && '...' || 'ubuntu-latest'` fallback every other conditionally-depot job in this file already uses.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_63f12996-baba-4e52-9262-7362598ed443) |
Purpose
Safety-net baseline, not a merge candidate as-is. This PR exists so real CI (full workspace tests across Linux/Windows/macOS/wasm, the
ecosystemjob, clippy, fmt) exercises the catch-up merge that local scoped checks couldn't fully cover — not to be merged intomainwithout further review. Kept as a standalone reference per the earlier "keep a copy in another branch" direction; this draft is the validation step on top of that, not a change of intent.What this is
upstream/main(astral-sh/ruff) merged downstream into this fork'smain— the fork stays the mainline (first parent), upstream's 1513 commits since the merge-base (8c930f5972841d899ff0586f9b8d45a85815a5d3) come in as the second parent via a real merge commit, not a rebase. 313 fork-only commits since that point are preserved untouched.This closes both "legitimate feature port" gaps flagged earlier without hand-porting anything:
RUF105and the human-readable rule-name selector machinery are now present, pulled in as part of the merge.Conflict resolution (11 files had real conflicts; ~26 more in the overlap surface auto-merged clean)
Each was traced to the fork's own commit history before choosing a side — never guessed:
AGENTS.md— upstream's file, fork's SPO/transcode paragraph re-inserted after the intro.Cargo.toml— union: upstream's dependency bumps + every fork-only path dep/exclude/patch kept.Cargo.lock— regenerated viacargo generate-lockfile, not hand-resolved.crates/ruff/src/lib.rs,crates/ruff_linter/src/rules/ruff/rules/sort_dunder_slots.rs,crates/ruff_server/tests/e2e/main.rs,crates/ty_server/tests/e2e/main.rs,crates/ty_python_semantic/src/types/narrow.rs,crates/ty_python_semantic/src/types/protocol_class.rs,crates/ruff_python_formatter/src/range.rs— took upstream's side; each verified semantically identical to the fork's own colliding clippy-1.97-sweep change viagit showon the fork's commit before deciding.crates/ruff_annotate_snippets/src/renderer/display_list.rs— modify/delete, followed upstream's restructure (vendored newer annotate-snippets)..github/workflows/ci.yaml,.pre-commit-config.yaml— auto-merged clean; hand-verified the fork's deliberate additions (Windowsruff_cpp_spolibclang-crash exclusion from ci: pull upstream ecosystem-ref fixes (bokeh, jrnl-org) + fork-side Windows libclang exclude #99; the pre-commit fixer-hook exclusions added after real data corruption) survived and grafted onto upstream's current file shape.python/ruff-ecosystem/ruff_ecosystem/defaults.py,scripts/check_ecosystem.py— no-op (fork's only change was the same two upstream ref-bump cherry-picks already in ci: pull upstream ecosystem-ref fixes (bokeh, jrnl-org) + fork-side Windows libclang exclude #99).rust-toolchain.toml— no conflict, both sides already1.97.1.Validation so far (local, scoped — this PR's CI is the real test)
RUF105/is_human_readable_names_enabledconfirmed present post-merge.cargo check -p <fork's own crates> -p ty -p ruff— clean.cargo clippyon the same scope — 1 pre-existing failure (iter_over_hash_type,crates/ruff_ruby_spo/src/menu_regions.rs:2208), confirmed via diff the merge touched zero files in that crate — prior fork debt, not introduced here, left untouched.cargo fmt --checkon the same scope — clean.cargo check/test was not run locally (too slow for 1512 commits of drift) — deferred to this PR's CI.ruff_r2ilcould not be validated at all locally (worktree-sandbox path collision, unrelated to the merge) — this PR's CI is the first real check for that crate.Known follow-ups, not blocking this PR
ruff_r2ilneeds a real build check from a non-nested checkout (blocked locally by sandbox, not by the merge).lsp-typesgit patch/vendor directory is now dead weight — upstream moved to a publishedgen-lsp-typescrate. Prints a harmlessunused patchwarning; candidate for a separate cleanup PR, not touched here.ruff_ruby_spoclippy lint above, unrelated to this merge.Test plan
git log --graphconfirms correct merge topology (fork main as first parent)Generated by Claude Code