test: add assertType coverage for untested type inference cases#80
Conversation
- isErr() narrowing (annotation existed but was untested) - instanceof narrowing on the true branch (pins known limitation: generics are lost, unwrap() becomes mixed) - match expression arm narrowing via instanceof (mixed) vs isOk() (preserves Ok<int>/Err<RuntimeException>) - match() method return type composition (U|V) - inspect()/inspectErr() type preservation - callback parameter inference for isOkAnd/isErrAnd/inspect/inspectErr - constructor inference for new Ok / new Err - conditional return resolution of unwrap/unwrapErr on generic receiver - unwrapOr/unwrapOrElse on concrete Ok/Err receivers
|
Warning Review limit reached
More reviews will be available in 37 minutes and 10 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #80 +/- ##
===========================================
Coverage 100.00% 100.00%
Complexity 40 40
===========================================
Files 2 2
Lines 80 80
===========================================
Hits 80 80
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
There was a problem hiding this comment.
Code Review
This pull request adds several PHPStan type assertion tests for the Result type (Ok/Err), covering type narrowing with isErr() and instanceof, match expressions, callback parameter inference, and unwrap variants. The review feedback correctly identifies that using never as a parameter type hint in a closure (line 267) is invalid in PHP and will cause a fatal error, suggesting to remove the type hint and let PHPStan infer it.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| { | ||
| assertType('int', $ok->unwrap()); | ||
| assertType('int', $ok->unwrapOr($default)); | ||
| assertType('int', $ok->unwrapOrElse(static fn (never $e): float => $fallback)); |
There was a problem hiding this comment.
PHPでは never 型は戻り値専用の型(return-only type)であり、関数の引数の型ヒントとして使用することはできません。このコードを実行しようとすると、Fatal error: Type never can only be used as a return type が発生します。
PHPStanの静的解析用ファイルであり直接実行されない場合でも、無効なPHP構文を避けるために、引数の型ヒントから never を削除することをお勧めします。unwrapOrElse の定義から、PHPStanは引数 $e を自動的に never として推論します。
assertType('int', $ok->unwrapOrElse(static fn ($e): float => $fallback));There was a problem hiding this comment.
Pull request overview
This PR expands PHPStan assertType coverage in tests/Types/result.php to validate previously untested type-inference and narrowing behaviors (notably isErr()-based narrowing, match expression arm narrowing, and callback/constructor inference), without changing the library implementation in src/.
Changes:
- Add
isErr()narrowing tests to cover both true/false branches (Err<E>vsOk<T>). - Add new coverage for
matchexpression arm narrowing andResult::match()return-type composition. - Add coverage for callback parameter inference, constructor inference (
new Ok(...)/new Err(...)), and conditional return types onunwrap*variants.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
tests/Types/result.phpの assertType 型テストを拡充し、アノテーションは実装済みなのに検証されていなかったケース(isErr()ナローイング等)と、match式・コールバック推論まわりの未カバーケースを追加する。ライブラリ本体(src/)の変更はなし。Changes
isErr()ナローイング:@phpstan-assert-if-true Err<E>/@phpstan-assert-if-false Ok<T>の両分岐を検証(これまでisOk()側のみテストされていた)instanceofナローイングの true 側分岐: 既知の制限としてピン留め — ジェネリクスが失われOk(型引数なし)になりunwrap()はmixedになるmatch式のアーム内ナローイング:instanceofアームではmixedになる一方、isOk()アームならunwrap()がintに解決されることを対で検証match()メソッド: 戻り値が両コールバックの戻り値型U|V(float|string)に合成されることを検証inspect()/inspectErr():Result<int, RuntimeException>を変えないことを検証isOkAnd/isErrAnd/inspect/inspectErrに渡した型宣言なしクロージャの引数がint/RuntimeExceptionに推論されることを検証new Ok($int)→Ok<int>、new Err($e)→Err<RuntimeException>Resultレシーバでのunwrap()/unwrapErr()、および具象Ok/ErrレシーバでのunwrapOr()/unwrapOrElse()が実行時に起こり得ない側の型を混ぜないことを検証Notes
instanceofベースの絞り込みはジェネリクスを失う(isOk()/isErr()経由なら保たれる)ことが判明。既存のtestInstanceofNarrowingが型引数なしのErrを期待していたのはこれが理由。該当テストには「既知の制限」コメントを付け、isOk()版の推奨を明記したnew Ok(42)→Ok<42>、fn => 0.5→0.5)を避けるため、リテラルではなく引数経由で値を渡しているVerification
phpstan analyse(level max)✅ /php-cs-fixer fix --dry-run✅ /phpunit --no-coverage✅ (69 tests, 111 assertions)