- 
                Notifications
    
You must be signed in to change notification settings  - Fork 1.7k
 
Description
Consider the following program:
class A {}
mixin M {}
class AM = A with M;
class B extends AM {}
class C {}
class D extends C {}
class E extends D {}
class F1 extends B implements E {}
class F2 extends B implements E {}
void f(bool b, F1 f1, F2 f2) {
  var x = b ? f1 : f2;
  x.expectStaticType<Exactly<B>>(); // Accepted by the analyzer.
}
void main() {}
typedef Exactly<X> = X Function(X);
extension<X> on X { X expectStaticType<Y extends Exactly<X>>() => this; }This program is accepted with no errors or warnings from the analyzer (Based on Dart SDK 3.9.0-333.0.dev). This shows that the inferred type of x is B. However, the superinterface graph above the operands to UP that gave rise to this outcome is as follows (specified here and here):
graph BT;
  Object --> Object?
  A --> Object
  M --> Object
  B --> AWithM["AM"]
  AWithM --> A
  AWithM --> M
  C --> Object
  D --> C
  E --> D
  F1 --> B
  F1 --> E
  F2 --> B
  F2 --> E
    This implies that B has been chosen in spite of the fact that it is not the only shared superinterface of F1 and F2 at depth 4, but the algorithm should choose the deepest shared superinterface which is at a depth that has exactly one node (this algorithm comes from Dart 1, but is used as the last case in the definition of UP).
It seems likely that this outcome could be caused by treating class AM = A with M; as the same as class AM extends A with M {}, which means that B would have depth 5 rather than 4.
However, the CFE gives x the type Object, which corresponds to a treatment where AM has depth 3 and B has depth 4. This means that the analyzer can be adjusted to do the same thing, without breaking any programs that are currently accepted by the CFE.