// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

class I<T> {}

class J<T> extends I<T> {}

class A<T> extends J<T> {}

extension<T> on I<T> {
  num get member {
    return T == int ? 0.5 : 1;
  }
}

extension<T> on A<T> {
  void member(T t) {}
}

exhaustiveInferred(
        A<num>
            a) => /*
             fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
             type=A<num>
            */
    switch (a) {
      A<int>(
        :var member
      ) /*space=A<int>(A<int>.member: void Function(int) (void Function(int)))*/ =>
        0,
      A<num>(
        :var member
      ) /*space=A<num>(A<num>.member: void Function(num) (void Function(num)))*/ =>
        1,
    };

exhaustiveTyped(
        A<num>
            a) => /*cfe.
             fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
             type=A<num>
            */ /*analyzer.
 fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
 type=A<num>
*/
    switch (a) {
      A<int>(
        :void Function(int) member
      ) /*space=A<int>(A<int>.member: void Function(int) (void Function(int)))*/ =>
        0,
      A<num>(
        :void Function(num) member
      ) /*space=A<num>(A<num>.member: void Function(num) (void Function(num)))*/ =>
        1,
    };

unreachable(
        A<num>
            a) => /*cfe.
             fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
             type=A<num>
            */ /*analyzer.
 fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
 type=A<num>
*/
    switch (a) {
      A<num>(
        :var member
      ) /*space=A<num>(A<num>.member: void Function(num) (void Function(num)))*/ =>
        1,
      A<int>(
        :var member
      ) /*cfe.
       error=unreachable,
       space=A<int>(A<int>.member: void Function(int) (void Function(int)))
      */ /*analyzer.
     error=unreachable,
     space=A<int>(A<int>.member: void Function(int) (void Function(int)))
    */
        =>
        0,
    };

nonExhaustiveRestricted(
        A<num>
            a) => /*cfe.
             fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
             type=A<num>
            */ /*analyzer.
 fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
 type=A<num>
*/
    switch (a) {
      A<num>(
        :void Function(num) member
      ) /*space=A<num>(A<num>.member: void Function(num) (void Function(num)))*/ =>
        1,
      A<int>(
        :var member
      ) /*cfe.
       error=unreachable,
       space=A<int>(A<int>.member: void Function(int) (void Function(int)))
      */ /*analyzer.
     error=unreachable,
     space=A<int>(A<int>.member: void Function(int) (void Function(int)))
    */
        =>
        0,
    };

intersection(o) {
  /*
   checkingOrder={Object?,Object,Null},
   fields={A<int>.member:void Function(int),A<num>.member:void Function(num)},
   subtypes={Object,Null},
   type=Object?
  */
  switch (o) {
    /*space=?*/ case A<int>(member: var member1) &&
          A<double>(member: var member2):
    /*space=A<int>(A<int>.member: void Function(int) (void Function(int)), A<num>.member: void Function(num) (void Function(num)))*/ case A<
              int>(member: var member1) &&
          A<num>(member: var member2):
  }
}

// TODO(johnniwinther): This should be exhaustive.
num exhaustiveMixed(
        I<num>
            i) => /*
 error=non-exhaustive:I<num>(member: double()),
 fields={I<num>.member:num,J<num>.member:num},
 type=I<num>
*/
    switch (i) {
      I<num>(:int member) /*space=I<num>(I<num>.member: int (num))*/ => member,
      J<num>(:double member) /*space=J<num>(J<num>.member: double (num))*/ =>
        member,
    };
