blob: f55fe0acbbc0f2c8b4c7db98c5119f250afc3ff2 [file] [log] [blame]
// 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: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;
void parseComponent(String source) {
env = new parser.Env(source);
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 {
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*");
}
}