| // Copyright (c) 2019, 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. |
| |
| import 'package:kernel/ast.dart'; |
| import 'package:kernel/core_types.dart' show CoreTypes; |
| import 'package:kernel/testing/mock_sdk_component.dart'; |
| import 'package:test/test.dart'; |
| import 'package:expect/expect.dart'; |
| import 'package:vm/bytecode/recursive_types_validator.dart'; |
| |
| main() { |
| Library lib; |
| Supertype objectSuper; |
| DartType intType; |
| DartType doubleType; |
| Class base; |
| RecursiveTypesValidator validator; |
| |
| Class addClass(String name, List<TypeParameter> typeParameters) { |
| Class cls = new Class( |
| name: name, supertype: objectSuper, typeParameters: typeParameters); |
| lib.addClass(cls); |
| return cls; |
| } |
| |
| setUp(() { |
| // Start with mock SDK libraries. |
| Component component = createMockSdkComponent(); |
| CoreTypes coreTypes = new CoreTypes(component); |
| objectSuper = coreTypes.objectClass.asThisSupertype; |
| intType = new InterfaceType(coreTypes.intClass); |
| doubleType = new InterfaceType(coreTypes.doubleClass); |
| |
| // Add the test library. |
| lib = new Library(Uri.parse('org-dartlang:///test.dart'), name: 'lib'); |
| lib.parent = component; |
| component.libraries.add(lib); |
| |
| // class Base<T> |
| base = addClass('Base', [new TypeParameter('T')]); |
| |
| validator = new RecursiveTypesValidator(); |
| }); |
| |
| tearDown(() {}); |
| |
| test('simple-recursive-type', () async { |
| // class Derived<T> extends Base<Derived<T>> |
| TypeParameter t = new TypeParameter('T'); |
| Class derived = addClass('Derived', [t]); |
| DartType derivedOfT = |
| new InterfaceType(derived, [new TypeParameterType(t)]); |
| DartType derivedOfInt = new InterfaceType(derived, [intType]); |
| derived.supertype = new Supertype(base, [derivedOfT]); |
| |
| validator.validateType(derivedOfT); |
| Expect.isTrue(validator.isRecursive(derivedOfT)); |
| |
| validator.validateType(derivedOfInt); |
| Expect.isTrue(validator.isRecursive(derivedOfInt)); |
| }); |
| |
| test('recursive-type-extends-instantiated', () async { |
| // class Derived<T> extends Base<Derived<Derived<int>>> |
| TypeParameter t = new TypeParameter('T'); |
| Class derived = addClass('Derived', [t]); |
| DartType derivedOfT = |
| new InterfaceType(derived, [new TypeParameterType(t)]); |
| DartType derivedOfInt = new InterfaceType(derived, [intType]); |
| DartType derivedOfDerivedOfInt = new InterfaceType(derived, [derivedOfInt]); |
| derived.supertype = new Supertype(base, [derivedOfDerivedOfInt]); |
| |
| validator.validateType(derivedOfT); |
| validator.validateType(derivedOfInt); |
| |
| Expect.isFalse(validator.isRecursive(derivedOfT)); |
| Expect.isTrue(validator.isRecursive(derivedOfInt)); |
| Expect.isTrue(validator.isRecursive(derivedOfDerivedOfInt)); |
| }); |
| |
| test('recursive-non-contractive-type', () async { |
| // class Derived<T> extends Base<Derived<Derived<T>>> |
| TypeParameter t = new TypeParameter('T'); |
| Class derived = addClass('Derived', [t]); |
| DartType derivedOfT = |
| new InterfaceType(derived, [new TypeParameterType(t)]); |
| DartType derivedOfInt = new InterfaceType(derived, [intType]); |
| DartType derivedOfDerivedOfT = new InterfaceType(derived, [derivedOfT]); |
| derived.supertype = new Supertype(base, [derivedOfDerivedOfT]); |
| |
| Expect.throws(() { |
| validator.validateType(derivedOfT); |
| }); |
| Expect.throws(() { |
| validator.validateType(derivedOfDerivedOfT); |
| }); |
| Expect.throws(() { |
| validator.validateType(derivedOfInt); |
| }); |
| }); |
| |
| test('mutually-recursive-types', () async { |
| // class Derived1<U> extends Base<Derived2<U>> |
| // class Derived2<V> extends Base<Derived1<V>> |
| TypeParameter u = new TypeParameter('U'); |
| Class derived1 = addClass('Derived1', [u]); |
| |
| TypeParameter v = new TypeParameter('V'); |
| Class derived2 = addClass('Derived2', [v]); |
| |
| DartType derived2OfU = |
| new InterfaceType(derived2, [new TypeParameterType(u)]); |
| derived1.supertype = new Supertype(base, [derived2OfU]); |
| |
| DartType derived1OfV = |
| new InterfaceType(derived1, [new TypeParameterType(v)]); |
| derived2.supertype = new Supertype(base, [derived1OfV]); |
| |
| DartType derived1OfU = |
| new InterfaceType(derived1, [new TypeParameterType(u)]); |
| DartType derived1OfInt = new InterfaceType(derived1, [intType]); |
| |
| DartType derived2OfV = |
| new InterfaceType(derived2, [new TypeParameterType(v)]); |
| DartType derived2OfInt = new InterfaceType(derived2, [intType]); |
| |
| validator.validateType(derived1OfU); |
| Expect.isTrue(validator.isRecursive(derived1OfU)); |
| |
| validator.validateType(derived1OfInt); |
| Expect.isTrue(validator.isRecursive(derived1OfInt)); |
| |
| validator.validateType(derived2OfV); |
| Expect.isTrue(validator.isRecursive(derived2OfV)); |
| |
| validator.validateType(derived2OfInt); |
| Expect.isTrue(validator.isRecursive(derived2OfInt)); |
| }); |
| |
| test('recursive-two-type-params', () async { |
| // class F<P1, P2> {} |
| // class E<Q1, Q2> extends F<E<Q1, int>, Q2> {} |
| TypeParameter p1 = new TypeParameter('P1'); |
| TypeParameter p2 = new TypeParameter('P2'); |
| Class f = addClass('F', [p1, p2]); |
| |
| TypeParameter q1 = new TypeParameter('Q1'); |
| TypeParameter q2 = new TypeParameter('Q2'); |
| Class e = addClass('E', [q1, q2]); |
| |
| DartType eOfQ1Int = |
| new InterfaceType(e, [new TypeParameterType(q1), intType]); |
| e.supertype = new Supertype(f, [eOfQ1Int, new TypeParameterType(q2)]); |
| |
| DartType eOfIntDouble = new InterfaceType(e, [intType, doubleType]); |
| |
| validator.validateType(eOfIntDouble); |
| validator.validateType(e.thisType); |
| |
| Expect.isFalse(validator.isRecursive(eOfIntDouble)); |
| Expect.isFalse(validator.isRecursive(e.thisType)); |
| }); |
| } |