// 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 'package:compiler/implementation/dart_types.dart';
import "package: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.length == 1);
        Expect.equals(element,
                      element.typeVariables.first.element.enclosingElement);
      }
      for (InterfaceType supertype in element.allSupertypesAndSelf.types) {
        if (!supertype.typeArguments.isEmpty) {
          Expect.listEquals(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.length == 1);
        Expect.equals(element,
                      element.typeVariables.first.element.enclosingElement);
      }
      for (InterfaceType supertype in element.allSupertypesAndSelf.types) {
        if (typeArguments.containsKey(supertype.element)) {
          Expect.listEquals(typeArguments[supertype.element],
                            supertype.typeArguments,
              "Type argument mismatch on supertype $supertype of $element.");
        } else if (!supertype.typeArguments.isEmpty) {
          Expect.listEquals(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.first;
    testSupertypes(D1, {A: [D1_T], B: [D1_T, instantiate(A, [D1_T])]});
    DartType D1_superclass_T = D1.superclass.typeVariables.first;
    testSupertypes(D1.superclass,
        {A: [D1_superclass_T],
         B: [D1_superclass_T, instantiate(A, [D1_superclass_T])]});
    DartType D2_T = D2.typeVariables.first;
    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.first;
    testSupertypes(F1, {A: [_], B: [_, instantiate(B, [F1_T, _])]});
    DartType F1_superclass_T = F1.superclass.typeVariables.first;
    testSupertypes(F1.superclass, {A: [_], B: [_, instantiate(B, [F1_superclass_T, _])]});
    DartType F2_T = F2.typeVariables.first;
    testSupertypes(F2, {A: [_], B: [_, instantiate(B, [F2_T, _])]});
  }));
}
