Skip to content

UnnecessaryExplicitTypeArguments: retain load-bearing witness in argument position on instance methods too#946

Merged
timtebeek merged 1 commit into
openrewrite:mainfrom
neil-mushell:neil-mushell/fix-unnecessary-explicit-type-arguments-argument-position
Jul 21, 2026
Merged

UnnecessaryExplicitTypeArguments: retain load-bearing witness in argument position on instance methods too#946
timtebeek merged 1 commit into
openrewrite:mainfrom
neil-mushell:neil-mushell/fix-unnecessary-explicit-type-arguments-argument-position

Conversation

@neil-mushell

@neil-mushell neil-mushell commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What's changed?

Generalizes UnnecessaryExplicitTypeArguments's argument-position guard to retain a type witness on instance methods too, not just static ones, when the witness's type variables aren't inferable from the call's own arguments. Removes the now-redundant shouldRetainOnStaticMethod helper in favor of applying canInferTypeArgumentsFromArguments uniformly — the same check already used for the sibling select-position branch.

What's your motivation?

The argument-position branch only guarded static methods (via shouldRetainOnStaticMethod) against removing a witness whose type variables aren't inferable from the call's own arguments. Instance methods used as arguments skipped that guard entirely, so a witness like t.<STATE_VALUE>source() passed to a generic static factory Transition.of(...) got stripped even though STATE_VALUE has no argument to infer it from and the factory itself provides no target type, leaving STATE_VALUE unresolved.

We hit this piloting the recipe against a state-machine interpreter with recursive/self-bounded generics (StateMachineInterpreter<STATE_VALUE extends Enum<STATE_VALUE>, ...>), where it silently broke compilation.

Anything in particular you'd like reviewers to focus on?

Whether folding the argument-position and select-position branches into one shared check is worth a larger refactor — they both now reduce to "retain unless inferable from the call's own arguments" and only diverge afterward on the overload-ambiguity check, which is argument-position-only.

Anyone you would like to review specifically?

No specific request — open to whoever's around.

Have you considered any alternatives or workarounds?

Considered keeping shouldRetainOnStaticMethod's name/shape and just widening its condition (adding || !isStatic or similar). Removed it instead since "static-only" naming became misleading once the check applies to both static and instance methods, and both branches already share canInferTypeArgumentsFromArguments.

Any additional context

Full module suite: 2147 tests, 0 regressions from this change (one pre-existing intermittent failure in AllBranchesIdenticalTest.collapseIdenticalBranchesPython, reproduced independent of this diff — a flaky Python-parser round-trip test unrelated to this recipe). Added both a negative-case test (witness retained, matching the bug) and a positive-case test (witness still removed when inference from the call's own arguments is possible) to make sure the fix doesn't over-correct into blanket retention.

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

…ment position on instance methods too

The argument-position branch only guarded static methods (via
shouldRetainOnStaticMethod) against removing a witness whose type
variables aren't inferable from the call's own arguments. Instance
methods used as arguments skipped that guard entirely, so a witness
like `t.<STATE_VALUE>source()` passed to a generic static factory
`Transition.of(...)` got stripped even though STATE_VALUE has no
argument to infer it from and the factory itself provides no target
type, leaving STATE_VALUE unresolved.

Generalize the check to apply regardless of static/instance, matching
the reasoning already used for the sibling select-position case.
@neil-mushell
neil-mushell force-pushed the neil-mushell/fix-unnecessary-explicit-type-arguments-argument-position branch from 5977e5c to 03032b8 Compare July 21, 2026 14:41

@timtebeek timtebeek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for coming back here with another round of fixes. Good to have this hardened against a code base with heavy usage.

@github-project-automation github-project-automation Bot moved this from In Progress to Ready to Review in OpenRewrite Jul 21, 2026
@timtebeek
timtebeek merged commit 1b15142 into openrewrite:main Jul 21, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants