Skip to content

Dart cannot be sure that the method argument is not null if the argument is used in a closure #1583

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

Closed
ghost opened this issue Apr 14, 2021 · 2 comments
Labels
state-duplicate This issue or pull request already exists

Comments

@ghost
Copy link

ghost commented Apr 14, 2021

@vadlit commented on Apr 8, 2021, 10:40 AM UTC:

By some reason Dart cannot be sure that the method argument is not null if the argument is used in a closure. Property 'isEven' cannot be accessed on 'int?' because it is potentially null

void main() {
  foo(1);
}

void foo(int? nullable) {
  Future.delayed(Duration(seconds:0)).then((_)
  {
    if (nullable == null) { 
      nullable = 5;
    }
    if (nullable == null) {
      return;
    }
    print(nullable.isEven);
  });
}

In this case, as far as I undestand, there's no chance that the 'nullable' argument suddenly becomes nullable after the 1st check, because it's just a method argument, not class field.
The problem is not reproduced if remove the first check.

Dart 2.12.2
Windows

This issue was moved by keertip from dart-lang/sdk#45629.

@ghost
Copy link
Author

ghost commented Apr 14, 2021

@eernstg commented on Apr 8, 2021, 11:59 AM UTC:

Cf. dart-lang/language#1247. It's possible that the flow analysis could give special treatment to the case where all references (read & write) to a given local variable occurs in the same function literal or local function, even though the variable is declared in an enclosing function.

@lrhn
Copy link
Member

lrhn commented Apr 22, 2021

The general issue here is that the exists a function which assigns to the variable, and we assume it can be invoked at any time. Even inside that function, we can't be sure that the same function won't be invoked again.
This code is so exceedingly simple that we can actually be sure nothing happens between the checks (== null calls no other code) and assignments (assigning to a local variable calls no other code). Most code isn't that simple, so it's not something we optimize for.

However, there is something we can do better here. We have a situation where all assignments to the variable assign a non-nullable value. We know that there is no assignment floating around which can make the variable null after we have checked that it's non-null.
After the

  if (nullable == null) {
    nullable = 5;
  }

we do know that nullable is non-null because it was, and there is no assignment to nullable anywhere which can invalidate that. Even if we don't know when this function is called, what state we start in or which code can run before, after or during the invocation, we still know that after proving that nullable is non-null by either failing at nullable == null or assigning 5 to nullable, it will stay non-nullable.

(I've done a proper move of the issue, to issue 1597, and will lock this move-bot version).

@lrhn lrhn closed this as completed Apr 22, 2021
@lrhn lrhn added the state-duplicate This issue or pull request already exists label Apr 22, 2021
@dart-lang dart-lang locked and limited conversation to collaborators Apr 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
state-duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

1 participant