language
language copied to clipboard
[Dart 3] Can't infer types in some cases
The compiler and analyzer are unable to infer types in some pretty clear cases. For example:
class A<T> { }
class C extends A<int> {}
class B<T extends A<S>, S> {
B(A<S> x);
}
void main() {
B(C());
}
This code results in the following error:
lib/main.dart:10:3:
Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<S>' of the type variable 'T' on 'B'.
- 'A' is from 'package:dartpad_sample/main.dart' ('lib/main.dart').
- 'Object' is from 'dart:core'.
B(C());
^
lib/main.dart:5:9:
Info: This is the type variable whose bound isn't conformed to.
class B<T extends A<S>, S> {
^
Error: Compilation failed.
Analyzer error:
Couldn't infer type parameter 'T'.
Tried to infer 'A<Object?>' for 'T' which doesn't work:
Type parameter 'T' is declared to extend 'A<S>' producing 'A<int>'.
Consider passing explicit type argument(s) to the generic.
Version: Dart SDK version: 3.0.0 (stable) (Thu May 4 01:11:00 2023 -0700) on "windows_x64"
Not even I can infer what you want T to be.
Not even I can infer what you want
Tto be.
T is not the problem, the compiler is correctly identifying it as A<int>. The problem is that the compiler is not inferring S as int.
The first line of the error you posted seems to indicate that the compiler, just like me, can't infer what T is supposed to be.
The error messages says that it tries to make T be A<Object?>, which is not a a subtype of A<S>. The analyzer helpfully tells us that A<S> is A<int>.
Not sure how or why, but a type parameter which is unconstrained by the function argument types and context type are usually not inferred to anything useful.
I admit that in this case, it would work if the compiler first inferred that S = int, and then used that information to infer that T = A<int>. That requires inferring S first and T second, which isn't completely unreasonable since T depends on S, but not the other way around. (While T extends A<S> can be seen as a constraint in both directions, it's not one which limits S.)
It can also be why changing B<T extends A<S>, S> to B<S, T extends A<S>> resolves the compiler error.
And then when you change it to:
class B<S, T extends A<S>> {
B(T x); // instead of B(A<S> x);
}
Then suddenly B is inferred to be B<dynamic, C>
So apparently T is inferred to be C correctly. And C is correctly inferred as A