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

Bug: Type inference of List parameter in method with restricted type parameter resulting in analysis error #45400

Closed
Abion47 opened this issue Mar 20, 2021 · 1 comment
Labels
closed-as-intended Closed as the reported issue is expected behavior

Comments

@Abion47
Copy link

Abion47 commented Mar 20, 2021

I'm creating this issue in response to a question that was asked today on StackOverflow.

As of Dart 2.12.0, the following code results in a static type error:

void main() {
  final nums = [1, 2.0, 3.5];
  final ints = [1, 2, 3];
  final doubles = [1.1, 2.2, 3.3];
  
  sums(nums);
  sums(ints);
  sums(doubles);
}

void sums<T extends num>(List<T> list) {
  T res = list[0];

  for (var i = 1; i < list.length; i++) {
    res = res + list[i];
  }

  print(res);
}
main.dart:15:15: Error: A value of type 'num' can't be assigned to a variable of type 'T'.
    res = res + list[i];
              ^

The same code when run in Dart 2.10.5 compiles successfully and prints the following:

6.5
6
6.6

When the sums method is altered to include the suggested fix, the error goes away in Dart 2.12.0:

void sums<T extends num>(List<T> list) {
  T res = list[0];

  for (var i = 1; i < list.length; i++) {
    res = res + list[i] as T;
  }

  print(res);
}

But when it is changed to use an addition-assignment operator, the error persists regardless of the cast. However, the static analysis error is hidden in the IDE (VS Code, DartPad) by a warning that suggests the cast is unnecessary:

void sums<T extends num>(List<T> list) {
  T res = list[0];

  for (var i = 1; i < list.length; i++) {
    res += list[i] as T; // IDE warning, error on `dart analyze` or on compile
  }

  print(res);
}

Both of these amended versions run flawlessly in Dart 2.10.5, with or without the cast.

This behavior has been confirmed on Mac OS 11.2.3 in VS Code (Dart extension 3.20.1) as well as the null-safety version of DartPad in Chrome.

@Abion47 Abion47 changed the title Type inference of List parameter in method with restricted type parameter resulting in analysis error Bug: Type inference of List parameter in method with restricted type parameter resulting in analysis error Mar 20, 2021
@lrhn
Copy link
Member

lrhn commented Mar 21, 2021

The difference is that res = res + list[i] as T; means res = (res + list[i]) as T;, whereas res += list[i] as T; means res = res + (list[i] as T);. The latter cast is unnecessary since list[i] already has type T.

The error comes from res having type T extends num, so all we know about res + something is that it returns num (that's what num.operator+ does, and all we know about T is that it implements num).
However, num is not assignable to T extends num without an implicit or explicit downcast, and Null Safety removed the implicit downcast. So, you need to cast the result.

Dart has added some special cases to the typing of int.+, and similar operators, to avoid errors like this in cases where you're just doing integer arithmetic. Those special cases do not extend to T extends num.

@lrhn lrhn added the closed-as-intended Closed as the reported issue is expected behavior label Mar 21, 2021
@lrhn lrhn closed this as completed Mar 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-as-intended Closed as the reported issue is expected behavior
Projects
None yet
Development

No branches or pull requests

2 participants