Skip to content

Reject identity comparison between distinct concrete types#5345

Open
SeanTAllen wants to merge 1 commit into
mainfrom
error-on-disjoint-concrete-is-comparison
Open

Reject identity comparison between distinct concrete types#5345
SeanTAllen wants to merge 1 commit into
mainfrom
error-on-disjoint-concrete-is-comparison

Conversation

@SeanTAllen
Copy link
Copy Markdown
Member

is and isnt between two distinct concrete entity types (any pair drawn from class, actor, primitive, struct) can never be true. The compiler now rejects these comparisons at compile time instead of silently folding them to false.

The rule is intentionally narrow: it fires only when both operand types resolve to a single concrete nominal definition. Comparisons involving traits, interfaces, unions, intersections, tuples, or type parameters continue to compile, since a future code change to those structural type sets could make the comparison meaningful. Two reifications of the same generic class (Array[U64] vs Array[U32]) share a single root entity definition and are also not flagged; type-argument disjointness is left to follow-up work. Two object end literals at distinct source locations synthesize different anonymous classes and are flagged.

Closes #1977

@SeanTAllen SeanTAllen added the changelog - changed Automatically add "Changed" CHANGELOG entry on merge label May 16, 2026
@ponylang-main ponylang-main added the discuss during sync Should be discussed during an upcoming sync label May 16, 2026
@SeanTAllen
Copy link
Copy Markdown
Member Author

Deferred scope: unions

This PR only flags is/isnt when both operand types are a single concrete nominal. Unions are deliberately out of scope — e.g., c is u where c: C and u: (D | E) (all three distinct concrete types) is not flagged today, even though the comparison is provably false.

Extending the rule to unions whose members are all concrete and collectively disjoint from the other operand would catch more cases, at the cost of more complex reasoning. Worth discussing as a follow-up.

@SeanTAllen
Copy link
Copy Markdown
Member Author

Deferred scope: tuples

Tuples are also out of scope for this PR. (c, d) is (e, f) where the element types are pairwise disjoint concrete types is not flagged today.

Extending the rule to tuples whose elements are pairwise disjoint concrete types would be a natural follow-up. Worth discussing.

`is` and `isnt` are object-identity operators: a value of one concrete
entity type can never be the same object as a value of a different
concrete entity type, so a comparison between them is provably false.
Today the compiler accepts these comparisons and codegen folds them to
the constant `false`. That hides what is almost always a bug — usually a
case where `==` is meant. Reject them at compile time.

Scope is deliberately narrow to avoid the "action at a distance" concern
discussed in #1977 and #1971: the rule fires only when both operand
types resolve to a single TK_NOMINAL bound to a concrete entity
definition (class, actor, primitive, or struct). Where the operand
types are unions, intersections, tuples, type parameters, or
trait/interface nominals, the code still compiles — a future addition or
removal of a type elsewhere in the program could make the comparison
meaningful. Two reifications of the same generic class (Array[U64] vs
Array[U32]) share a single root entity definition and are also not
flagged; reasoning about disjointness of type arguments is left to
future work. Two `object end` literals at different source locations
synthesize distinct anonymous classes and are flagged.

The implementation sits in the verify pass next to the existing
"identity comparison with a new object" diagnostic; the && short-circuit
in verify_is ensures a single expression cannot trigger both errors.

Closes #1977
@SeanTAllen SeanTAllen force-pushed the error-on-disjoint-concrete-is-comparison branch from 913c489 to fa8af64 Compare May 22, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog - changed Automatically add "Changed" CHANGELOG entry on merge discuss during sync Should be discussed during an upcoming sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compiler error on identity comparison for concrete types.

2 participants