Reject identity comparison between distinct concrete types#5345
Reject identity comparison between distinct concrete types#5345SeanTAllen wants to merge 1 commit into
Conversation
|
Deferred scope: unions This PR only flags 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. |
|
Deferred scope: tuples Tuples are also out of scope for this PR. 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
913c489 to
fa8af64
Compare
isandisntbetween 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 tofalse.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]vsArray[U32]) share a single root entity definition and are also not flagged; type-argument disjointness is left to follow-up work. Twoobject endliterals at distinct source locations synthesize different anonymous classes and are flagged.Closes #1977