dart-lang / language

Design of the Dart language
Other
2.65k stars 201 forks source link

Inferred type too general? #2069

Closed modulovalue closed 8 months ago

modulovalue commented 2 years ago

Hello,

Could it be a bug that the type of listA isn't List<Base<All>> but List<Object>?

My expectation was that the type of listA would be the most specific type possible i.e. List<Base<All>> in this case and not List<Object>.

void main() {
  const listA = [Err(), Leaf()];
  print(listA.runtimeType); // prints List<Object>
  const listB = <Base<All>>[Err(), Leaf()];
  print(listB.runtimeType); // prints List<Base<All>>
}

abstract class Base<H> {}

class Err implements Base<All> {
  const Err();
}

class Leaf implements Base<Valid> {
  const Leaf();
}

abstract class All {}

abstract class Valid implements All {}
eernstg commented 2 years ago

In the case where we're computing the least upper bound of Err and Leaf, the least upper bound algorithm in Dart uses a rule, let's call it Rold, which has been part of the language since Dart 1. In general, Rold is used to find the least upper bound of two class types that aren't generic instantiations of the same class.

The rule Rold is specified here.

This rule is rather simplistic and it yields upper bounds that are considerably less tight than they could be. For example, the least upper bound of Err and Leaf turns out to be Object rather than Base<All>. The basic idea is that it selects the most special shared superinterface of the operands as a whole, and it never applies the least upper bound algorithm on subexpressions of those types. This means that Dart avoids some termination issues that had come up in the context of Java. Moreover, the rule Rold has also been kept unchanged all the time because it is a seriously breaking change to introduce a different rule.

But it is certainly a known issue that the least upper bound algorithm delivers suboptimal results in this particular case. See https://github.com/dart-lang/language/labels/least-upper-bound for more discussions about improving the least upper bounds algorithm.

modulovalue commented 1 year ago

Note: this issue is relevant to https://github.com/dart-lang/language/issues/844 and https://github.com/spebbe/dartz/issues/32. Anyone trying to do something similar will eventually come across this.

modulovalue commented 8 months ago

I'm going to close this issue because I don't think that it's likely that many people would benefit from focusing on this issue alone.

I think that a fresh discussion around #844 (and, more broadly, use cases for phantom types, e.g., https://github.com/dart-lang/language/issues/2865 & https://github.com/dart-lang/language/issues/3273) would be needed to make discussing this particular issue worthwhile.