language icon indicating copy to clipboard operation
language copied to clipboard

Assignment expressions in `if`-statements don't correctly promote nullable variables

Open skylon07 opened this issue 1 year ago • 5 comments

This program errors:

void main() {
  String? getString() => "asdf";

  String? someString;
  if ((someString = getString()) != null) {
    // errors:
    // "The property 'isNotEmpty' can't be unconditionally accessed because the receiver can be 'null'."
    print(someString.isNotEmpty);
  }
}

This one does not:

void main() {
  String? getString() => "asdf";

  String? someString;
  someString = getString();
  if (someString != null) {
    // does not error
    print(someString.isNotEmpty);
  }
}

I feel like the first program shouldn't error... Doesn't it guarantee that someString is not nullable just as much as the second program does? I might be wrong here -- I don't usually use assignment syntax in if-statements like this. (If you're curious, I'm using this syntax to store the results of a chain of nullable RegExp matches, which looks neater than having several assignments put between unchained if-statements.)

Infos

  • Dart 3.3.1 (stable) (Wed Mar 6 13:09:19 2024 +0000) on "macos_arm64"
  • on macos / Version 14.0 (Build 23A344)
  • locale is en-US

skylon07 avatar Mar 18 '24 06:03 skylon07

There is a request for generalisation of the flow analysis in https://github.com/dart-lang/language/issues/1224, in order to get a larger set of reasons for promoting a local variable. In that issue the topic is that if (foo?.something == somethingNotNull) ... could promote foo to have a non-nullable type in the true continuation (because the condition would necessarily be false when foo == null).

This issue is similar in that it is a request for detecting that x can't be null in the true continuation of (x = e) != null.

I'll move this issue to the language repository and label it in a way which is similar to the existing issue.

eernstg avatar Mar 18 '24 09:03 eernstg

@stereotype441, @johnniwinther, it seems that we may have a group of somewhat similar requests in this area (at least, #1224 seems related). Would you prefer to make it a single issue covering all the variants? What's the best labeling?

eernstg avatar Mar 18 '24 09:03 eernstg

A single meta-issue with links to individual issues for concrete enhancement ideas is probably better than combining different ideas into one issue, in case we choose to do some, but not all, of them.

lrhn avatar Mar 19 '24 14:03 lrhn

Maybe we'd just create a new label (e.g., enhanced-promotion) and then use that for proposals about new ways to establish that a given promotion is justified.

eernstg avatar Mar 19 '24 16:03 eernstg

This came up in some internal code recently. Here's a stripped-down version of what the code looked like (with the identifier names and types changed to protect IP):

void main() {
  int? x;
  [
    for (var y in [1, 2, null, 4, 5])
      if ((x = y) != null) x!.isEven, // It would be nice if the `!` in `x!` were unnecessary
  ];
}

stereotype441 avatar Jul 25 '24 22:07 stereotype441