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

Unexpected runtime error using singleWhere on collection of nullable types #47563

Closed
spkersten opened this issue Oct 28, 2021 · 1 comment
Closed
Labels
closed-duplicate Closed in favor of an existing report

Comments

@spkersten
Copy link
Contributor

The following code has no static failures (as expected):

// @dart=2.12
 
void main() {
  foo(<int>[3]);
} 

int? foo(List<int?> x) {
  x.singleWhere(
    (_) => true,
    orElse: () {
      return null;
    },
  );
} 

but it fails with:

Unhandled exception:
type '() => Null' is not a subtype of type '(() => int)?' of 'orElse'
#0      ListMixin.singleWhere (dart:collection/list.dart)
...

This is unexpected. For methods that modify the collection (x) there might be some awareness about problems with broken covariance (while also not great), but for something that doesn't modify the collection (like singleWhere) it's even less obvious.

Might be related to #33841.

Using:

Dart SDK version: 2.14.3 (stable) (Wed Sep 29 13:10:26 2021 +0200) on "macos_x64"
@lrhn
Copy link
Member

lrhn commented Oct 28, 2021

This is as good as it gets with unsound covariant generics. You'd get a similar error just doing x.add(null);.

The problem, as you point out, is that you pass a List<int> to something expecting a List<int?>. That's allowed because List<int> is a subtype of List<int?>, but it's unsound for any member of List where the element type occurs contravariantly . That includes add and singleWhere.
The problem exists for any method where you need to produce a value of the element type in any other way than by reading it from the list, not just those trying to put that element into the list (although those are the most obvious ones). The singleWhere method claims to return a value which could be put into the list, and here it doesn't.

It's not special to null safety either, you would get a similar error for:

void main() {
  foo(<int>[3]);
} 

int? foo(List<num> x) {
  x.singleWhere(
    (_) => true,
    orElse: () {
      return 0.0;
    },
  );
  // or just: x.add(0.0);
} 

See the language issue tracker for proposed solutions to that unsoundness.

So, working as currently intended. It is a known problem.

@lrhn lrhn closed this as completed Oct 28, 2021
@lrhn lrhn added the closed-duplicate Closed in favor of an existing report label Oct 28, 2021
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

2 participants