language icon indicating copy to clipboard operation
language copied to clipboard

[Dart 3] Can't infer types in some cases

Open MohiuddinM opened this issue 2 years ago • 6 comments
trafficstars

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"

MohiuddinM avatar May 14 '23 21:05 MohiuddinM

Not even I can infer what you want T to be.

mateusfccp avatar May 15 '23 21:05 mateusfccp

Not even I can infer what you want T to 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.

MohiuddinM avatar May 15 '23 21:05 MohiuddinM

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.

mateusfccp avatar May 15 '23 22:05 mateusfccp

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.)

lrhn avatar May 15 '23 22:05 lrhn

It can also be why changing B<T extends A<S>, S> to B<S, T extends A<S>> resolves the compiler error.

MohiuddinM avatar May 15 '23 22:05 MohiuddinM

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 but the fact that T extends A<S> is not being used to determine that S must be int.

marcov-dart avatar Jun 06 '24 19:06 marcov-dart