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

Nullability promotion issue with local variable usages in iterators #51183

Closed
AlexV525 opened this issue Jan 31, 2023 · 5 comments
Closed

Nullability promotion issue with local variable usages in iterators #51183

AlexV525 opened this issue Jan 31, 2023 · 5 comments
Labels
closed-duplicate Closed in favor of an existing report

Comments

@AlexV525
Copy link
Contributor

This tracker is for issues related to: Analyzer.

When I was developing in flutter_tools, I found a weird promotion with the nullability of a local variable.

image

A simple example for this issue:

void main() {
  final String? test;
  final List<String> testList = [];
  if (1 * 2 == 2) {
    test = 'Yes';
  } else {
    test = null;
  }
  if (test != null) {
    testList.removeWhere((e) => e.contains(test)); // <-- Raises exception.
  }
}

I was wondering at this point why the variable cannot be proofed as non-null.

@eernstg
Copy link
Member

eernstg commented Jan 31, 2023

The reason why test isn't considered non-null in the invocation of contains is actually the very fact that test occurs in that particular location!

The point is that the function literal (e) => e.contains(test) evaluates to a function object, and the flow analysis of Dart does not attempt to keep track of all the locations where that function object might be called. For instance, if we're calling a method (basically any method of any receiver) then we don't know the exact piece of code which is going to run, and that piece of code might then have access to this function object, so it might be called. If that could occur at a point in time where test has the value null then it would be unsound to consider test non-nullable in this function literal.

We have had requests for an improved analysis of this situation. Perhaps it would be possible to recognize that the function object could not possibly be called at any point in time where test == null. However, this is a complex step in the analysis, and it is a well-known fact that there are some situations where the current analysis isn't able to detect some guarantees that a human reader would see rather easily.

In any case, you can help the flow analysis by introducing a new local variable whose value is never nullable:

void main() {
  final String? test;
  final List<String> testList = [];
  if (1 * 2 == 2) {
    test = 'Yes';
  } else {
    test = null;
  }
  if (test != null) {
    var test1 = test;
    testList.removeWhere((e) => e.contains(test1));
  }
}

@eernstg eernstg added closed-as-intended Closed as the reported issue is expected behavior and removed closed-as-intended Closed as the reported issue is expected behavior labels Jan 31, 2023
@eernstg
Copy link
Member

eernstg commented Jan 31, 2023

@stereotype441, I searched for an issue which is requesting improvements in the flow analysis of variables whose value is read (not written) in a local function object, but didn't find anything spot on. Are you aware of any such issue? Otherwise, I think we could move this issue to the language repository and make it the go-to issue for this feature request.

@asashour
Copy link
Contributor

asashour commented Jan 31, 2023

This is a duplicate of dart-lang/language#1536, for which there is CL which makes the OP test pass, in sdk/277880

@eernstg
Copy link
Member

eernstg commented Jan 31, 2023

@asashour, that was exactly what I was looking for, thanks!

@eernstg eernstg closed this as completed Jan 31, 2023
@eernstg eernstg added the closed-duplicate Closed in favor of an existing report label Jan 31, 2023
@AlexV525
Copy link
Contributor Author

Thanks! The request for promoting final expressions also looks great too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-duplicate Closed in favor of an existing report
Projects
None yet
Development

No branches or pull requests

3 participants