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
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -89,7 +89,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
89
89
-**Single generic argument on collections bound to the wrong template parameter.** Writing `Collection<SectionTranslation>` on a class with `@template TKey of array-key` and `@template TValue` assigned the argument to `TKey` (by position), leaving `TValue` unsubstituted. When fewer generic arguments are provided than template parameters and the leading parameters have key-like bounds (`array-key`, `int`, `string`), the arguments are now right-aligned so they bind to the value parameters. Method-level template parameters whose bound parameter was not passed at the call site and defaults to `null` now resolve to `null` instead of remaining as raw template names. Together these fixes mean `Collection<SectionTranslation>::first()` correctly resolves to `SectionTranslation|null`.
90
90
-**Nullable return types losing `|null` after template substitution.** When a method declared `@return TValue|null` and `TValue` was substituted with a concrete class through `@extends`, the `|null` component was silently dropped. Hover showed `AdminUser` instead of `AdminUser|null` for calls like `AdminUser::first()`. The docblock type extraction pipeline now preserves nullable unions so that `|null` survives through substitution, hover display, and variable type resolution.
91
91
-**Loop-body assignments not visible inside the same loop iteration.** When a variable was initialized as `null` and reassigned later in a loop body, code earlier in the loop (reached on subsequent iterations) only saw `null`. The variable resolution walker now pre-scans the entire loop body for assignments before the positional walk, so the union of all assignments is available at every point inside the loop. Combined with `!== null` narrowing, variables like `$lastPaidEnd` correctly resolve to the assigned class type. Applies to `foreach`, `while`, `for`, and `do-while` loops.
92
-
-**`@mixin` referencing a template parameter now resolves.** When a class declares `@template T` and `@mixin T`, the mixin name is substituted with the concrete type from the generic arguments. For example, a wrapper class `Subclient<EventsApi>` with `@mixin TWraps` now pulls in `EventsApi`'s methods instead of silently ignoring the mixin because no class named `TWraps` exists.
92
+
-**`@mixin` referencing a template parameter now resolves.** When a class declares `@template T` and `@mixin T`, the mixin name is substituted with the concrete type from the generic arguments. For example, a wrapper class `Subclient<EventsApi>` with `@mixin TWraps` now pulls in `EventsApi`'s methods instead of silently ignoring the mixin because no class named `TWraps` exists. The initial fix only handled the ancestor-walk path (`ChildClass extends Wrapper<Concrete>`); the direct-property-access path (`/** @var Wrapper<Concrete> */ public $prop`) now also works. Additionally, mixin names that are template parameters are no longer FQN-resolved during parsing (which turned `TWraps` into `Namespace\TWraps`, breaking the template-param match).
93
93
-**Eloquent `where{Property}()` methods from docblock-only `@property` tags.** Models that declare columns only via `@property` annotations (without `$casts`, `$fillable`, etc.) now correctly get `where{PropertyName}()` methods on `Builder<Model>`.
0 commit comments