Skip to content

test: add assertType coverage for untested type inference cases#80

Merged
valbeat merged 1 commit into
mainfrom
test/assert-type-coverage
Jun 10, 2026
Merged

test: add assertType coverage for untested type inference cases#80
valbeat merged 1 commit into
mainfrom
test/assert-type-coverage

Conversation

@valbeat

@valbeat valbeat commented Jun 10, 2026

Copy link
Copy Markdown
Owner

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|Vfloat|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.50.5)を避けるため、リテラルではなく引数経由で値を渡している

Verification

  • Local (PHP 8.4.7): phpstan analyse(level max)✅ / php-cs-fixer fix --dry-run ✅ / phpunit --no-coverage ✅ (69 tests, 111 assertions)

- 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
@valbeat valbeat self-assigned this Jun 10, 2026
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@valbeat, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1b128fa6-24e6-41ad-ab0d-9cb10f7fc826

📥 Commits

Reviewing files that changed from the base of the PR and between 81c6834 and 87a5772.

📒 Files selected for processing (1)
  • tests/Types/result.php
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/assert-type-coverage

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (81c6834) to head (87a5772).
✅ All tests successful. No failed tests found.

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           
Flag Coverage Δ
unittests 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread tests/Types/result.php
{
assertType('int', $ok->unwrap());
assertType('int', $ok->unwrapOr($default));
assertType('int', $ok->unwrapOrElse(static fn (never $e): float => $fallback));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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));

@valbeat valbeat marked this pull request as ready for review June 10, 2026 09:05
Copilot AI review requested due to automatic review settings June 10, 2026 09:05
@valbeat valbeat merged commit 80412a1 into main Jun 10, 2026
10 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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> vs Ok<T>).
  • Add new coverage for match expression arm narrowing and Result::match() return-type composition.
  • Add coverage for callback parameter inference, constructor inference (new Ok(...) / new Err(...)), and conditional return types on unwrap* variants.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants