Skip to content

Remove IdenticalEqual#2248

Merged
sanmai merged 10 commits intoinfection:masterfrom
sanmai:fix/remove-IdenticalEqual-EqualIdentical
Jul 8, 2025
Merged

Remove IdenticalEqual#2248
sanmai merged 10 commits intoinfection:masterfrom
sanmai:fix/remove-IdenticalEqual-EqualIdentical

Conversation

@sanmai
Copy link
Copy Markdown
Member

@sanmai sanmai commented Jun 25, 2025

Fixes #2111

This feels like a breaking change to me, so I guess it could be a good idea to make a minor version release before merging this, if we agree to do that.

  • Fix tests
  • Revert EqualIdentical removal

Copy link
Copy Markdown
Member

@maks-rafalko maks-rafalko left a comment

Choose a reason for hiding this comment

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

I personally have never used these 2 mutators since we disabled them by default. So LGTM

identical operator (`===`)).
TXT
,
MutatorCategory::SEMANTIC_REDUCTION,
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.

I know the other one is disabled because it is a semantic addition which is non-sense to have, but what was it about this one?

Copy link
Copy Markdown
Member Author

@sanmai sanmai Jun 25, 2025

Choose a reason for hiding this comment

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

That's a good question. For some reason we had it disabled too. What do you think is the best path?

I guess we could enable it back.

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.

Ah I think it was simply redundant with the not equal ones in the end

@sanmai sanmai marked this pull request as ready for review June 25, 2025 13:04
@sanmai sanmai changed the title Remove IdenticalEqual, EqualIdentical Remove IdenticalEqual Jun 26, 2025
@sanmai sanmai marked this pull request as draft July 8, 2025 13:05
@staabm
Copy link
Copy Markdown
Contributor

staabm commented Jul 8, 2025

This feels like a breaking change to me

agree, I also feel its a breaking change.

on github.com I found a single reference (outside of infection/* repos)

@maks-rafalko
Copy link
Copy Markdown
Member

maks-rafalko commented Jul 8, 2025

agree, I also feel its a breaking change.

but we are on 0.x, and it was disabled by default - not a big deal.

on github.com I found a single reference (outside of infection/* repos)

https://github.com/kubawerlos/php-cs-fixer-custom-fixers/blob/0cf921cf9aee50ac3091839325f5cf38ab189b97/.dev-tools/src/InfectionConfigBuilder.php#L24

it's disabled and located in a const named UNWANTED_MUTATORS :) so it just confirms we shouldn't care about it IMO

@sanmai sanmai marked this pull request as ready for review July 8, 2025 14:08
@sanmai sanmai enabled auto-merge (squash) July 8, 2025 14:08
The test was incorrectly removing EqualIdentical when it should only
remove IdenticalEqual. This restores the test case that verifies
parsing of 'AssignmentEqual,EqualIdentical' mutator input.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@sanmai sanmai merged commit 8e177c8 into infection:master Jul 8, 2025
47 checks passed
@sanmai sanmai deleted the fix/remove-IdenticalEqual-EqualIdentical branch July 20, 2025 07:18
@Ocramius
Copy link
Copy Markdown
Contributor

Just ran into this while doing upgrades: I used this mutator, as it is important to check for identity vs equality in some domains (example: ORMs, serializers).

Should not have been dropped, tbh.

Ocramius added a commit to Roave/BackwardCompatibilityCheck that referenced this pull request Nov 26, 2025
This sort of mutation was disabled in this codebase, but it was valuable in ORMs/serializers.

Ref: infection/infection#2248
Ref: infection/infection#2248 (comment)
Ref: infection/infection@8e177c8

Fixes:

```
In InvalidSchema.php line 60:

  "/github/workspace/infection.json.dist" does not match the expected JSON sc
  hema:
   - [mutators] The property IdenticalEqual is not defined and the definition
   does not allow additional properties
```
@theofidry
Copy link
Copy Markdown
Member

@Ocramius you can now create a custom one where you add it back.

I admit I don't understand what it would allow you to check though. Note that it is === -> ==, not == -> ===

@sanmai
Copy link
Copy Markdown
Member Author

sanmai commented Nov 26, 2025

I would really love to understand the use-case 🙏

@Ocramius
Copy link
Copy Markdown
Contributor

In an identity-map-backed repository, the test must verify that object-hash-level identity is used.

For example, written naively:

public function remove(object $toRemove) {
    foreach ($this->identityMap as $key => $item) {
        if ($toRemove === $item) {
            unset($this->identityMap[$key]);
        }
    }
}

This is a case where === -> == can lead to a mutation that hides equality-based object manipulation.

In such a test, the author would need to add 2 equal, non-same objects to the identityMap, then remove one: the mutation highlights how such an identity could've been skipped.

@theofidry
Copy link
Copy Markdown
Member

theofidry commented Nov 27, 2025

@Ocramius this should still be tested I think?

To step back for a moment: what we want here is to prove that this piece of code is bug free.

Now let's say a developer accidentally changes this strict equality for a loose equality and the tests are green:

public function remove(object $toRemove) {
    foreach ($this->identityMap as $key => $item) {
        if ($toRemove == $item) {
            unset($this->identityMap[$key]);
        }
    }
}

Then you will have the equal to identity mutation that will kick in:

public function remove(object $toRemove) {
    foreach ($this->identityMap as $key => $item) {
-        if ($toRemove == $item) {
+        if ($toRemove === $item) {
            unset($this->identityMap[$key]);
        }
    }
}

Then you have two scenarios:

  1. tests fails: would be that the claimed contract is untrue. So either the documentation of the contract is incorrect, or there is no test testing that contract (this can happen when you generate tests & harden them based on the current code, without any verification that it does what you really wanted in the first place).
  2. tests passes: The mutation is uncovered, and in this case shows the bug you wanted to guard against.

@Ocramius
Copy link
Copy Markdown
Contributor

@theofidry didn't you just say this is === -> ==? 🤔

maks-rafalko added a commit to infection/site that referenced this pull request Jan 2, 2026
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.

Smarter IdenticalEqual mutator

5 participants