// Copyright (c) 2013, 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.

library mixin_typevariable_test;

import 'package:expect/expect.dart';
import "package:async_helper/async_helper.dart";
import 'type_test_helper.dart';
import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart"
       show Element, ClassElement;

void main() {
  testMixinSupertypes();
  testNonTrivialSubstitutions();
}

void testMixinSupertypes() {
  asyncTest(() => TypeEnvironment.create(r"""
      class S<S_T> {}
      class M1<M1_T> {}
      class M2<M2_T> {}
      class M3<M3_T> {}
      
      class C1<C1_T> extends S<C1_T> with M1<C1_T>, M2<C1_T>, M3<C1_T> {}
      class C2<C2_T> = S<C2_T> with M1<C2_T>, M2<C2_T>, M3<C2_T>;
      """, expectNoWarningsOrErrors: true).then((env) {

    ClassElement Object = env.getElement('Object');
    ClassElement S = env.getElement('S');
    ClassElement M1 = env.getElement('M1');
    ClassElement M2 = env.getElement('M2');
    ClassElement M3 = env.getElement('M3');
    ClassElement C1 = env.getElement('C1');
    ClassElement C2 = env.getElement('C2');

    ClassElement C1_S_M1_M2_M3 = C1.superclass;
    ClassElement C1_S_M1_M2 = C1_S_M1_M2_M3.superclass;
    ClassElement C1_S_M1 = C1_S_M1_M2.superclass;

    ClassElement C2_S_M1_M2 = C2.superclass;
    ClassElement C2_S_M1 = C2_S_M1_M2.superclass;

    void testSupertypes(ClassElement element) {
      if (element != Object) {
        Expect.isTrue(element.typeVariables.slowLength() == 1);
        Expect.equals(element,
                      element.typeVariables.head.element.enclosingElement);
      }
      for (InterfaceType supertype in element.allSupertypesAndSelf.types) {
        if (!supertype.typeArguments.isEmpty) {
          Expect.equals(element.typeVariables, supertype.typeArguments,
              "Type argument mismatch on supertype $supertype of $element.");
        } else {
          Expect.equals(Object, supertype.element);
        }
      }
    }

    testSupertypes(Object);
    testSupertypes(S);
    testSupertypes(M1);
    testSupertypes(M2);
    testSupertypes(C1_S_M1);
    testSupertypes(C1_S_M1_M2);
    testSupertypes(C1_S_M1_M2_M3);
    testSupertypes(C1);
    testSupertypes(C2_S_M1);
    testSupertypes(C2_S_M1_M2);
    testSupertypes(C2);
  }));
}

void testNonTrivialSubstitutions() {
  asyncTest(() => TypeEnvironment.create(r"""
      class _ {}
      class A<A_T> {}
      class B<B_T, B_S> {}
      
      class C1<C1_T> extends A with B {}
      class C2<C2_T> = A with B;
      
      class D1<D1_T> extends A<D1_T> with B<D1_T, A<D1_T>> {}
      class D2<D2_T> = A<D2_T> with B<D2_T, A<D2_T>>;
      
      class E1<E1_T> extends A<_> with B<_, A<_>> {}
      class E2<E2_T> = A<_> with B<_, A<_>>;
      
      class F1<F1_T> extends A<_> with B<_, B<F1_T, _>> {}
      class F2<F2_T> = A<_> with B<_, B<F2_T, _>>;
      """, expectNoWarningsOrErrors: true).then((env) {
    DartType _dynamic = env['dynamic'];
    DartType _ = env['_'];

    ClassElement Object = env.getElement('Object');
    ClassElement A = env.getElement('A');
    ClassElement B = env.getElement('B');
    ClassElement C1 = env.getElement('C1');
    ClassElement C2 = env.getElement('C2');
    ClassElement D1 = env.getElement('D1');
    ClassElement D2 = env.getElement('D2');
    ClassElement E1 = env.getElement('E1');
    ClassElement E2 = env.getElement('E2');
    ClassElement F1 = env.getElement('F1');
    ClassElement F2 = env.getElement('F2');

    ClassElement C1_A_B = C1.superclass;
    ClassElement D1_A_B = D1.superclass;
    ClassElement E1_A_B = E1.superclass;
    ClassElement F1_A_B = F1.superclass;

    void testSupertypes(ClassElement element,
                        Map<ClassElement, List<DartType>> typeArguments) {
      if (element != Object) {
        Expect.isTrue(element.typeVariables.slowLength() == 1);
        Expect.equals(element,
                      element.typeVariables.head.element.enclosingElement);
      }
      for (InterfaceType supertype in element.allSupertypesAndSelf.types) {
        if (typeArguments.containsKey(supertype.element)) {
          Expect.listEquals(typeArguments[supertype.element],
                            supertype.typeArguments.toList(),
              "Type argument mismatch on supertype $supertype of $element.");
        } else if (!supertype.typeArguments.isEmpty) {
          Expect.equals(element.typeVariables, supertype.typeArguments,
              "Type argument mismatch on supertype $supertype of $element.");
        } else {
          Expect.equals(Object, supertype.element);
        }
      }
    }

    testSupertypes(C1, {A: [_dynamic], B: [_dynamic, _dynamic]});
    testSupertypes(C1.superclass, {A: [_dynamic], B: [_dynamic, _dynamic]});
    testSupertypes(C2, {A: [_dynamic], B: [_dynamic, _dynamic]});

    DartType D1_T = D1.typeVariables.head;
    testSupertypes(D1, {A: [D1_T], B: [D1_T, instantiate(A, [D1_T])]});
    DartType D1_superclass_T = D1.superclass.typeVariables.head;
    testSupertypes(D1.superclass,
        {A: [D1_superclass_T],
         B: [D1_superclass_T, instantiate(A, [D1_superclass_T])]});
    DartType D2_T = D2.typeVariables.head;
    testSupertypes(D2, {A: [D2_T], B: [D2_T, instantiate(A, [D2_T])]});

    testSupertypes(E1, {A: [_], B: [_, instantiate(A, [_])]});
    testSupertypes(E1.superclass, {A: [_], B: [_, instantiate(A, [_])]});
    testSupertypes(E2, {A: [_], B: [_, instantiate(A, [_])]});

    DartType F1_T = F1.typeVariables.head;
    testSupertypes(F1, {A: [_], B: [_, instantiate(B, [F1_T, _])]});
    DartType F1_superclass_T = F1.superclass.typeVariables.head;
    testSupertypes(F1.superclass, {A: [_], B: [_, instantiate(B, [F1_superclass_T, _])]});
    DartType F2_T = F2.typeVariables.head;
    testSupertypes(F2, {A: [_], B: [_, instantiate(B, [F2_T, _])]});
  }));
}
