blob: fdb27ebed3cfd4f98ac3a82205ac6c6f968286a0 [file] [log] [blame]
// Copyright (c) 2020, 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:expect/expect.dart" show Expect;
import 'package:kernel/ast.dart';
import 'package:kernel/src/dart_type_equivalence.dart';
import 'package:kernel/testing/type_parser_environment.dart';
void run() {
// Simple types.
areEqual("int", "int");
notEqual("int", "String");
// Simple types with nullabilities.
areEqual("int?", "int?");
notEqual("int", "int?");
notEqual("int?", "String?");
areEqual("int?", "int?", ignoreAllNullabilities: true);
areEqual("int", "int?", ignoreAllNullabilities: true);
notEqual("int?", "String?", ignoreAllNullabilities: true);
areEqual("int?", "int?", ignoreTopLevelNullability: true);
areEqual("int", "int?", ignoreTopLevelNullability: true);
notEqual("int?", "String?", ignoreTopLevelNullability: true);
// 1-level deep types.
areEqual("List<int?>?", "List<int?>?");
notEqual("List<int?>?", "List<int?>");
notEqual("List<int?>?", "List<int>?");
notEqual("List<int?>?", "List<int>");
areEqual("List<int?>?", "List<int?>?", ignoreAllNullabilities: true);
areEqual("List<int?>?", "List<int?>", ignoreAllNullabilities: true);
areEqual("List<int?>?", "List<int>?", ignoreAllNullabilities: true);
areEqual("List<int?>?", "List<int>", ignoreAllNullabilities: true);
areEqual("List<int?>?", "List<int?>?", ignoreTopLevelNullability: true);
areEqual("List<int?>?", "List<int?>", ignoreTopLevelNullability: true);
notEqual("List<int?>?", "List<int>?", ignoreTopLevelNullability: true);
notEqual("List<int?>?", "List<int>", ignoreTopLevelNullability: true);
// Top types.
areEqual("dynamic", "dynamic");
notEqual("dynamic", "Object?");
notEqual("dynamic", "Object*");
notEqual("dynamic", "void");
areEqual("Object?", "Object?");
notEqual("Object?", "Object*");
notEqual("Object?", "void");
areEqual("Object*", "Object*");
notEqual("Object*", "void");
areEqual("void", "void");
notEqual("FutureOr<dynamic>", "void");
notEqual("FutureOr<FutureOr<Object?>>", "Object*");
notEqual("FutureOr<FutureOr<FutureOr<Object*>?>>?", "dynamic");
notEqual("FutureOr<Object?>", "FutureOr<Object?>?");
notEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<Object?>?>?");
notEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<dynamic>?>?");
areEqual("dynamic", "Object?", equateTopTypes: true);
areEqual("dynamic", "Object*", equateTopTypes: true);
areEqual("dynamic", "void", equateTopTypes: true);
areEqual("Object?", "Object*", equateTopTypes: true);
areEqual("Object?", "void", equateTopTypes: true);
areEqual("Object*", "void", equateTopTypes: true);
areEqual("FutureOr<dynamic>", "void", equateTopTypes: true);
areEqual("FutureOr<FutureOr<Object?>>", "Object*", equateTopTypes: true);
areEqual("FutureOr<FutureOr<FutureOr<Object*>?>>?", "dynamic",
equateTopTypes: true);
areEqual("FutureOr<Object?>", "FutureOr<Object?>?", equateTopTypes: true);
areEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<Object?>?>?",
equateTopTypes: true);
areEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<dynamic>?>?",
equateTopTypes: true);
areEqual("Object?", "Object*", ignoreAllNullabilities: true);
areEqual("FutureOr<Object?>", "FutureOr<Object?>?",
ignoreAllNullabilities: true);
areEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<Object?>?>?",
ignoreAllNullabilities: true);
notEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<dynamic>?>?",
ignoreAllNullabilities: true);
areEqual("FutureOr<Object?>", "FutureOr<Object?>?",
ignoreTopLevelNullability: true);
notEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<Object?>?>?",
ignoreTopLevelNullability: true);
notEqual("FutureOr<FutureOr<Object?>>", "FutureOr<FutureOr<dynamic>?>?",
ignoreTopLevelNullability: true);
// Generic function types.
notEqual("<T extends dynamic>() ->? int", "<T extends Object?>() -> int?");
notEqual("<T extends dynamic>() ->? int", "<T extends Object?>() -> int?",
equateTopTypes: true);
notEqual("<T extends dynamic>() ->? int", "<T extends Object?>() -> int?",
ignoreAllNullabilities: true);
notEqual("<T extends dynamic>() ->? int", "<T extends Object?>() -> int?",
ignoreTopLevelNullability: true);
notEqual("<T extends dynamic>() ->? int", "<T extends Object?>() -> int?",
equateTopTypes: true, ignoreTopLevelNullability: true);
areEqual("<T extends dynamic>() ->? int", "<T extends Object?>() -> int?",
equateTopTypes: true, ignoreAllNullabilities: true);
notEqual("<T extends dynamic>() -> T?", "<S extends Object?>() -> S?");
areEqual("<T extends dynamic>() -> T?", "<S extends Object?>() -> S?",
equateTopTypes: true);
notEqual("<T extends dynamic>() -> T", "<S extends FutureOr<void>>() -> S?");
notEqual("<T extends dynamic>() -> T", "<S extends FutureOr<void>>() -> S?",
equateTopTypes: true);
notEqual("<T extends dynamic>() -> T", "<S extends FutureOr<void>>() -> S?",
ignoreAllNullabilities: true);
areEqual("<T extends dynamic>() -> T", "<S extends FutureOr<void>>() -> S?",
equateTopTypes: true, ignoreAllNullabilities: true);
areEqual("<T>(<S>() -> void) -> void", "<X>(<Y>() -> void) -> void");
notEqual("<T>(<S extends void>() -> void) -> void",
"<X>(<Y extends Object?>() -> void) -> void");
notEqual("<T>(<S extends void>() -> void) -> void",
"<X>(<Y extends Object?>() -> void) -> void",
ignoreAllNullabilities: true);
// Free type variables.
areEqual("T", "T", typeParameters: "T");
notEqual("T?", "T", typeParameters: "T");
notEqual("T", "S",
typeParameters: "T, S",
equateTopTypes: true,
ignoreAllNullabilities: true);
notEqual("T & int?", "T & int", typeParameters: "T");
notEqual("T & int?", "T & int",
typeParameters: "T", ignoreTopLevelNullability: true);
areEqual("T & int?", "T & int",
typeParameters: "T", ignoreAllNullabilities: true);
// Check that normalization is out of the scope of the equivalence, even with
// the most permissive flags.
notEqual("Never?", "Null",
equateTopTypes: true, ignoreAllNullabilities: true);
notEqual("FutureOr<Never>", "Future<Never>",
equateTopTypes: true, ignoreAllNullabilities: true);
notEqual("FutureOr<Object>", "Object",
equateTopTypes: true, ignoreAllNullabilities: true);
// Typedef types.
areEqual("Typedef<int>", "Typedef<int>");
notEqual("Typedef<String>", "Typedef<num>");
notEqual("Typedef<num?>?", "Typedef<num>");
notEqual("Typedef<num?>?", "Typedef<num>", ignoreTopLevelNullability: true);
areEqual("Typedef<num?>?", "Typedef<num>", ignoreAllNullabilities: true);
notEqual("Typedef<Object?>?", "Typedef<dynamic>");
notEqual("Typedef<Object?>?", "Typedef<dynamic>",
ignoreTopLevelNullability: true);
notEqual("Typedef<Object?>?", "Typedef<dynamic>",
ignoreAllNullabilities: true);
notEqual("Typedef<Object?>?", "Typedef<dynamic>", equateTopTypes: true);
areEqual("Typedef<Object?>?", "Typedef<dynamic>",
equateTopTypes: true, ignoreTopLevelNullability: true);
}
void areEqual(String type1, String type2,
{String typeParameters = '',
bool equateTopTypes = false,
bool ignoreAllNullabilities = false,
bool ignoreTopLevelNullability = false}) {
Env env =
new Env("typedef Typedef<T> () -> T;\n", isNonNullableByDefault: true)
..extendWithTypeParameters(typeParameters);
DartType t1 = env.parseType(type1);
DartType t2 = env.parseType(type2);
List<String> flagNamesForDebug = [
if (equateTopTypes) "equateTopTypes",
if (ignoreAllNullabilities) "ignoreAllNullabilities",
if (ignoreTopLevelNullability) "ignoreTopLevelNullability",
];
print("areEqual(${type1}, ${type2}"
"${flagNamesForDebug.map((f) => ", $f").join()})");
Expect.isTrue(
new DartTypeEquivalence(env.coreTypes,
equateTopTypes: equateTopTypes,
ignoreAllNullabilities: ignoreAllNullabilities,
ignoreTopLevelNullability: ignoreTopLevelNullability)
.areEqual(t1, t2),
"Expected '${type1}' and '${type2}' to be equal "
"with flags ${flagNamesForDebug.map((f) => "'$f'").join(", ")}.");
print("areEqual(${type2}, ${type1}"
"${flagNamesForDebug.map((f) => ", $f").join()})");
Expect.isTrue(
new DartTypeEquivalence(env.coreTypes,
equateTopTypes: equateTopTypes,
ignoreAllNullabilities: ignoreAllNullabilities,
ignoreTopLevelNullability: ignoreTopLevelNullability)
.areEqual(t2, t1),
"Expected '${type2}' and '${type1}' to be equal "
"with flags ${flagNamesForDebug.map((f) => "'$f'").join(", ")}.");
}
void notEqual(String type1, String type2,
{String typeParameters = '',
bool equateTopTypes = false,
bool ignoreAllNullabilities = false,
bool ignoreTopLevelNullability = false}) {
Env env =
new Env("typedef Typedef<T> () -> T;\n", isNonNullableByDefault: true)
..extendWithTypeParameters(typeParameters);
DartType t1 = env.parseType(type1);
DartType t2 = env.parseType(type2);
List<String> flagNamesForDebug = [
if (equateTopTypes) "equateTopTypes",
if (ignoreAllNullabilities) "ignoreAllNullabilities",
if (ignoreTopLevelNullability) "ignoreTopLevelNullability",
];
print("notEqual(${type1}, ${type2}"
"${flagNamesForDebug.map((f) => ", $f").join()})");
Expect.isFalse(
new DartTypeEquivalence(env.coreTypes,
equateTopTypes: equateTopTypes,
ignoreAllNullabilities: ignoreAllNullabilities,
ignoreTopLevelNullability: ignoreTopLevelNullability)
.areEqual(t1, t2),
"Expected '${type1}' and '${type2}' to be not equal "
"with flags ${flagNamesForDebug.map((f) => "'$f'").join(", ")}.");
print("notEqual(${type2}, ${type1}"
"${flagNamesForDebug.map((f) => ", $f").join()})");
Expect.isFalse(
new DartTypeEquivalence(env.coreTypes,
equateTopTypes: equateTopTypes,
ignoreAllNullabilities: ignoreAllNullabilities,
ignoreTopLevelNullability: ignoreTopLevelNullability)
.areEqual(t2, t1),
"Expected '${type2}' and '${type1}' to be not equal "
"with flags ${flagNamesForDebug.map((f) => "'$f'").join(", ")}.");
}
void main() => run();