You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -54,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
54
54
-**`@var` without variable name for array access.**`/** @var array<int, Customer> */` followed by `$thing = []; $thing[0]->` now resolves the element type. Previously `find_iterable_raw_type_in_source` only matched annotations that explicitly named the variable (e.g. `/** @var array<int, Customer> $thing */`). The scanner now also matches no-variable-name `@var` annotations when the line immediately following the docblock is an assignment to the target variable. Works with `array<K, V>`, `list<V>`, `array<V>`, and all other generic iterable forms.
55
55
-**Inferred element type from array literals.**`$thing = [new Customer()]; $thing[0]->` now resolves to `Customer`. When an array literal contains positional (non-keyed) entries like `new ClassName()`, the element types are inferred and combined into a `list<Type>` annotation. Previously only string-keyed entries (for array shapes) and push-style assignments (`$var[] = expr`) were tracked; positional entries were silently discarded. Mixed arrays with both keyed and positional entries infer the positional elements as `list<>` when no string keys are present.
56
56
-**Inline array literal with index access.**`[Customer::first()][0]->` now resolves to the element type. Subject extraction recognises inline array literals (bracket pairs without a `$var` prefix) and produces a structured subject. The resolver splits the literal from the index segments, resolves each comma-separated element via call-chain or `new` expression resolution, and returns the element classes. The inline-literal handler runs before the enum-case/static-member check so that subjects containing `::` inside brackets are not misinterpreted.
57
+
-**`$this` in callable parameter types resolves to receiver class.** When a method signature uses `$this` or `static` in a callable parameter type (e.g. `@param callable($this, mixed): $this`), inferred closure parameters now resolve to the receiver class rather than the class the user is editing. Previously, `Builder::when(true, function ($query) { $query-> })` inside a controller would infer `$query` as the controller class. Now it correctly resolves to the Builder. Works for instance method calls, static method calls, and arrow functions.
57
58
-**Inline array element function calls.**`end($customers)->`, `current($this->users)->`, and similar inline uses of array element-extracting functions (`end`, `current`, `reset`, `next`, `prev`, `array_pop`, `array_shift`) now resolve to the element type. Previously this only worked when the result was assigned to a variable (`$last = end($customers); $last->`). The resolver now detects known array functions in the inline call path, resolves the first argument's iterable type (supporting plain variables with docblock/assignment scanning, call chains like `Customer::get()->all()`, static calls, and property access), extracts the generic element type, and returns the corresponding class.
58
59
-**Generator TSend inference inside nested control flow.**`$var = yield $expr` inside `while`, `if`, `foreach`, or other nested blocks now correctly resolves `$var` to the TSend type from the enclosing generator's `@return Generator<TKey, TValue, TSend, TReturn>` annotation. Previously `find_enclosing_return_type` was called with the cursor offset, so its backward brace scan stopped at the innermost block's `{` (e.g. the `if`'s opening brace) instead of reaching the function's opening brace. The call now uses the method/function body's opening brace offset directly from the AST, which is immune to intermediate control-flow braces. Yield-based TValue inference (`yield $var`) was already unaffected because the text-based body scan operates on the full function body.
59
60
-**Callable parameter type parsing in union types.**`extract_callable_param_types` now handles callable signatures wrapped in unions like `(Closure(Builder<TModel>): mixed)|null`, `callable(Collection<int, TValue>, int): mixed|null`, and `null|callable(Order): bool`. Previously the parser treated the entire union as one token and failed to find the callable signature. The `split_type_token` tokenizer was also fixed to keep generic suffixes like `Collection<int, User>|null` and parenthesized groups like `(Closure(X): Y)|null` as single tokens instead of splitting at the closing `>`, `}`, or `)`. This enables closure parameter inference for Laravel methods like `Builder::whereHas()`, `BuildsQueries::chunk()`, and `Builder::with()`, where the callback parameter types use these union patterns.
Copy file name to clipboardExpand all lines: docs/todo-laravel.md
+13-49Lines changed: 13 additions & 49 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -73,43 +73,7 @@ benefit) and an **Effort** estimate (implementation complexity):
73
73
74
74
---
75
75
76
-
#### 1. `$this` in inferred callable parameter types resolves to wrong class
77
-
78
-
|||
79
-
|---|---|
80
-
|**Impact**| ★★ — Manifests only when closure params are untyped; most IDE-aware codebases type-hint explicitly. Affects `when()`, `tap()`, and similar higher-order Eloquent/Collection methods. |
81
-
|**Effort**| ★ — Replace literal `$this`/`static` tokens with the receiver's FQN in `infer_callable_params_from_receiver` before returning. |
82
-
83
-
When a closure parameter is untyped and the inference system extracts
84
-
callable param types from the called method's signature, `$this` in
85
-
the extracted type resolves to the **calling class** (the class
86
-
containing the user's code) instead of the class that declares the
0 commit comments