| // 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. |
| |
| // @dart = 2.9 |
| |
| import "package:async_helper/async_helper.dart" show asyncTest; |
| |
| import "package:expect/expect.dart" show Expect; |
| |
| import "package:kernel/ast.dart"; |
| |
| import 'package:kernel/testing/type_parser_environment.dart' as parser; |
| |
| final Uri libraryUri = Uri.parse("org-dartlang-test:///library.dart"); |
| |
| abstract class LegacyUpperBoundTest { |
| parser.Env env; |
| Library coreLibrary; |
| Library testLibrary; |
| |
| bool get isNonNullableByDefault; |
| |
| void parseComponent(String source) { |
| env = |
| new parser.Env(source, isNonNullableByDefault: isNonNullableByDefault); |
| assert( |
| env.component.libraries.length == 2, |
| "The test component is expected to have exactly two libraries: " |
| "the core library and the test library."); |
| Library firstLibrary = env.component.libraries.first; |
| Library secondLibrary = env.component.libraries.last; |
| if (firstLibrary.importUri.scheme == "dart" && |
| firstLibrary.importUri.path == "core") { |
| coreLibrary = firstLibrary; |
| testLibrary = secondLibrary; |
| } else { |
| assert( |
| secondLibrary.importUri.scheme == "dart" && |
| secondLibrary.importUri.path == "core", |
| "One of the libraries is expected to be 'dart:core'."); |
| coreLibrary = secondLibrary; |
| testLibrary = firstLibrary; |
| } |
| } |
| |
| DartType getLegacyLeastUpperBound( |
| DartType a, DartType b, Library clientLibrary); |
| |
| void checkLegacyUpTypes( |
| DartType a, DartType b, DartType expected, Library clientLibrary) { |
| DartType actual = getLegacyLeastUpperBound(a, b, clientLibrary); |
| Expect.equals(expected, actual); |
| } |
| |
| void checkLegacyUp(String type1, String type2, String expectedType) { |
| checkLegacyUpTypes(env.parseType(type1), env.parseType(type2), |
| env.parseType(expectedType), testLibrary); |
| } |
| |
| Future<void> test() { |
| return asyncTest(() async { |
| await test_getLegacyLeastUpperBound_expansive(); |
| await test_getLegacyLeastUpperBound_generic(); |
| await test_getLegacyLeastUpperBound_nonGeneric(); |
| }); |
| } |
| |
| /// Copy of the tests/language/least_upper_bound_expansive_test.dart test. |
| Future<void> test_getLegacyLeastUpperBound_expansive() async { |
| await parseComponent(""" |
| class N<T>; |
| class C1<T> extends N<N<C1<T*>*>*>; |
| class C2<T> extends N<N<C2<N<C2<T*>*>*>*>*>; |
| """); |
| |
| // The least upper bound of C1<int> and N<C1<String>> is Object since the |
| // supertypes are |
| // {C1<int>, N<N<C1<int>>>, Object} for C1<int> and |
| // {N<C1<String>>, Object} for N<C1<String>> and |
| // Object is the most specific type in the intersection of the supertypes. |
| checkLegacyUp("C1<int*>*", "N<C1<String*>*>*", "Object*"); |
| |
| // The least upper bound of C2<int> and N<C2<String>> is Object since the |
| // supertypes are |
| // {C2<int>, N<N<C2<N<C2<int>>>>>, Object} for C2<int> and |
| // {N<C2<String>>, Object} for N<C2<String>> and |
| // Object is the most specific type in the intersection of the supertypes. |
| checkLegacyUp("C2<int*>*", "N<C2<String*>*>*", "Object*"); |
| } |
| |
| Future<void> test_getLegacyLeastUpperBound_generic() async { |
| await parseComponent(""" |
| class A; |
| class B<T> implements A; |
| class C<U> implements A; |
| class D<T, U> implements B<T*>, C<U*>; |
| class E implements D<int*, double*>; |
| class F implements D<int*, bool*>; |
| """); |
| |
| checkLegacyUp( |
| "D<int*, double*>*", "D<int*, double*>*", "D<int*, double*>*"); |
| checkLegacyUp("D<int*, double*>*", "D<int*, bool*>*", "B<int*>*"); |
| checkLegacyUp("D<int*, double*>*", "D<bool*, double*>*", "C<double*>*"); |
| checkLegacyUp("D<int*, double*>*", "D<bool*, int*>*", "A*"); |
| checkLegacyUp("E*", "F*", "B<int*>*"); |
| } |
| |
| Future<void> test_getLegacyLeastUpperBound_nonGeneric() async { |
| await parseComponent(""" |
| class A; |
| class B; |
| class C implements A; |
| class D implements A; |
| class E implements A; |
| class F implements C, D; |
| class G implements C, D; |
| class H implements C, D, E; |
| class I implements C, D, E; |
| """); |
| |
| checkLegacyUp("A*", "B*", "Object*"); |
| checkLegacyUp("A*", "Object*", "Object*"); |
| checkLegacyUp("Object*", "B*", "Object*"); |
| checkLegacyUp("C*", "D*", "A*"); |
| checkLegacyUp("C*", "A*", "A*"); |
| checkLegacyUp("A*", "D*", "A*"); |
| checkLegacyUp("F*", "G*", "A*"); |
| checkLegacyUp("H*", "I*", "A*"); |
| } |
| } |