Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False positive with == considered as always false when using generic records #4745

Open
rrousselGit opened this issue Sep 9, 2023 · 2 comments
Labels
false-positive P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@rrousselGit
Copy link

Consider the following code:

typedef GenericRecord<T> = (T a,);

const GenericRecord<int> _default = (42,);

void fn<T>(GenericRecord<T> record) {
  print(record == _default);
}

This code will cause the following warning:

The type of the right operand ('(int)') isn't a subtype or a supertype of the left operand ('(T)').

But that is incorrect. If we do fn((42,)) then this code will correctly print true

@bwilkerson
Copy link
Member

According to the specification:

A record type A is a subtype of record type B iff they have same shape and the types of all fields of A are subtypes of the corresponding field types of B.

While the record types have the same shape, the type int is not a subtype of T, nor is T a subtype of int. The lint warning is technically correct.

(Note that the lint isn't attempting to find places where the equality check is guaranteed to return false, it's just identifying a situation in which there is a high probability that the equality will always be false. It will also have a false positive if you are comparing two variables of unrelated class types A and B if the two variables have a value that's an instance of a type C that is a subtype of both A and B.)

I do agree that the lint (unrelated_type_equality_checks) might need to be loosened to allow records of the same shape to be compared, at least when one of the types is a type parameter type. I'm not sure whether it currently special cases type parameters for non-record types, so we'll need to consider whether to do so in both cases, only for records, or for neither.

@rrousselGit
Copy link
Author

I personally would expect generics to be replaced with their constraints when evaluating this check.

In:

fn<T>() {
  A<T> a;
  A<int> b;
  if (a == b) {...}
}

I'd expect this to behave as if it was comparing A<Object?> with A<int> – which should be reasonable, in the same way that comparing Object? with int is reasonable too.

Whereas with:

fn<T extends String>() {
  A<T> a;
  A<int> b;
  if (a == b) {...}
}

Then a == b here should likely be considered as a problem.

@bwilkerson bwilkerson added false-positive P2 A bug or feature request we're likely to work on labels Sep 18, 2023
@srawlins srawlins added the type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) label Apr 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
false-positive P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

3 participants