dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.2k stars 1.57k forks source link

record's complex generics inference seems problematic #53891

Open CoderBuck opened 11 months ago

CoderBuck commented 11 months ago
image

code:

class ValueBuilder<T> {
  final T data;
  final Function(T value) builder;

  ValueBuilder({required this.data, required this.builder});
}

class ValueBuilder2<T1, T2> {
  final (T1 data1, T2 data2) data;
  final Function(T1 value1, T2 value2) builder;

  ValueBuilder2({required this.data, required this.builder});
}

void main() {
  ValueBuilder(
    data: 1,
    builder: (value) { // value is int, fine
    },
  );
  ValueBuilder2(
    data: (1,2),
    builder: (value1, value2) { // <===> value1 and value2 is Object? , but i expect is int
      value1++;
    },
  );
  var valueBuilder2 = ValueBuilder2( // valueBuilder2 is ValueBuilder2<int, int>
    data: (1,2),
    builder: (value1, value2) { // <===> value1 and value2 is Object? , but i expect is int
      value1++;
    },
  );
  ValueBuilder2<int, int> valueBuilder3 = ValueBuilder2( // // valueBuilder3 is ValueBuilder2<int, int>
    data: (1,2),
    builder: (value1, value2) { // <===> value1 and value2 is int, fine
      value1++;
    },
  );
}
➜  ~ dart --version
Dart SDK version: 3.1.3 (stable) (Tue Sep 26 14:25:13 2023 +0000) on "macos_x64"
eernstg commented 11 months ago

Looks like horizontal inference might need to be updated to take record types into account. @stereotype441, WDYT?

Here is a more concise example:

void f<X, Y>((X, Y) pair, void Function(X x, Y y) func) {}
void main() => f((1, 2), (x, y) => x + y); // Error because parameters have type `Object?`.
lrhn commented 11 months ago

Agree that it's record-related. If I change Erik's example to:

void f<X, Y>(Pair<X, Y> pair, void Function(X x, Y y) func) {}
void main() => f(const Pair(1, 2),
    (x, y) => x + y); // Error because parameters have type `Object?`.

class Pair<X, Y> {
  final X x;
  final Y y;
  const Pair(this.x, this.y);
}

then it works. Records should be at least as easy to infer as the corresponding class.

Seems to be Analyzer only, Dart2JS (in DartPad) accepts the program.