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

[analyzer] Analyzer reports misleading type when type-promotion #49235

Open
AlexV525 opened this issue Jun 11, 2022 · 5 comments
Open

[analyzer] Analyzer reports misleading type when type-promotion #49235

AlexV525 opened this issue Jun 11, 2022 · 5 comments
Labels
analyzer-ux area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. P3 A lower priority bug or feature request type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@AlexV525
Copy link
Contributor

AlexV525 commented Jun 11, 2022

This tracker is for issues related to Analyzer.

Summary

Consider the code:

Object? _testVariable;

void main() {
  final Object? testVariable = _testVariable;
  if (testVariable is A?) {
    Usage<A>(testVariable);
  } else if (testVariable is B?) {
    Usage<B>(testVariable); // <-- Reports error here.
  }
}

class A {}

class B {}

class Usage<T> {
  const Usage(this.field);
  
  final T? field;
}

The analyzer gives the error: The argument type 'Object' can't be assigned to the parameter type 'B?'. (argument_type_not_assignable)

is A? judges A and Null, but the after flow only promotes non-nullable without the type context. As I can imagine it should be types that is! A?.

Changing is B? to is B solves the issue, though it seems to be lost nullability here, the is A? has already judged the nullability.

Version Information

Dart SDK: 2.17.3

@lrhn lrhn added area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels Jun 11, 2022
@bwilkerson
Copy link
Member

@stereotype441 How difficult would it be to add a context message here explaining why promotion didn't work as expected?

@pq pq added the P3 A lower priority bug or feature request label Jun 13, 2022
@AlexV525 AlexV525 changed the title Analyzer reports misleading type when type-promotion [analyzer] Analyzer reports misleading type when type-promotion Jun 24, 2022
@AlexV525
Copy link
Contributor Author

AlexV525 commented Jul 7, 2023

Hi guys, do we have any thoughts or progress here?

@eernstg
Copy link
Member

eernstg commented Jul 7, 2023

Just a random drive-by comment: At else, flow analysis knows that testVariable is Object? and also that testVariable is! A? (note: that's "is not"). In particular, testVariable is not null. So the type of testVariable at that point becomes Object. And we can't promote from Object to B? because B? isn't a subtype of Object.

Any explanation that shows the promoted type at else would probably be quite helpful.

Pragmatically, @AlexV525, you might want to use a different construct where the flow analysis doesn't promote as aggressively from one case to the next:

Object? _testVariable;

void main() {
  final Object? testVariable = _testVariable;
  switch (testVariable) {
    case A? _:
      Usage<A>(testVariable);
    case B? _: // At this point `testVariable` has type `Object?` and is promoted to `B?`.
      Usage<B>(testVariable);
    /* default: no-op */
  }
}

class A {}

class B {}

class Usage<T> {
  const Usage(this.field);
  final T? field;
}

The reason why a switch statement or expression doesn't promote (much) based on the knowledge that a certain sequence of pattern matching steps failed is discussed here and here.

@stereotype441, you might have some further comments, is this working as expected?

@AlexV525
Copy link
Contributor Author

@eernstg That makes more sense if is! A? equals to is! A and is! Null as you said. Here I'd just thinking that it's is! A or is! Null because A? means A || Null.

@eernstg
Copy link
Member

eernstg commented Jul 17, 2023

That makes more sense if is! A? equals to is! A and is! Null as you said. Here I'd just thinking that it's is! A or is! Null because A? means A || Null.

It's 'and' rather than 'or' because of pure logic (De Morgan's laws). So you could say that we have e is! A? which means ! (e is A?), that is ! (e is A || e is Null), that is e is! A && e is! Null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
analyzer-ux area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. P3 A lower priority bug or feature request type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

6 participants