mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:29:48 +00:00
Implement runtime type equality.
Change-Id: I603b5147d7d7e6d8e7267be9c861324b575f259d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134041 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
5d7f3093fd
commit
d550879d9d
201
pkg/analyzer/lib/src/dart/element/runtime_type_equality.dart
Normal file
201
pkg/analyzer/lib/src/dart/element/runtime_type_equality.dart
Normal file
|
@ -0,0 +1,201 @@
|
|||
// 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:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_algebra.dart';
|
||||
import 'package:analyzer/src/dart/element/type_visitor.dart';
|
||||
import 'package:analyzer/src/generated/type_system.dart';
|
||||
|
||||
class RuntimeTypeEqualityHelper {
|
||||
final TypeSystemImpl _typeSystem;
|
||||
|
||||
RuntimeTypeEqualityHelper(TypeSystemImpl typeSystem)
|
||||
: _typeSystem = typeSystem;
|
||||
|
||||
/// Return `true` if runtime types [T1] and [T2] are equal.
|
||||
///
|
||||
/// nnbd/feature-specification.md#runtime-type-equality-operator
|
||||
bool equal(DartType T1, DartType T2) {
|
||||
var N1 = _typeSystem.normalize(T1);
|
||||
var N2 = _typeSystem.normalize(T2);
|
||||
return const RuntimeTypeEqualityVisitor().visit(N1, N2);
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeTypeEqualityVisitor extends DartTypeVisitor1<bool, DartType> {
|
||||
const RuntimeTypeEqualityVisitor();
|
||||
|
||||
@override
|
||||
bool defaultDartType(DartType T1, DartType T2) {
|
||||
throw UnimplementedError('(${T1.runtimeType}) $T1');
|
||||
}
|
||||
|
||||
bool visit(DartType T1, DartType T2) {
|
||||
return DartTypeVisitor1.visit(T1, this, T2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitDynamicType(DynamicTypeImpl T1, DartType T2) {
|
||||
return identical(T1, T2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitFunctionType(FunctionType T1, DartType T2) {
|
||||
if (T2 is FunctionType) {
|
||||
var typeParameters = _typeParameters(T1.typeFormals, T2.typeFormals);
|
||||
if (typeParameters == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool equal(DartType T1, DartType T2) {
|
||||
T1 = typeParameters.T1_substitution.substituteType(T1);
|
||||
T2 = typeParameters.T2_substitution.substituteType(T2);
|
||||
return visit(T1, T2);
|
||||
}
|
||||
|
||||
if (!equal(T1.returnType, T2.returnType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var T1_parameters = T1.parameters;
|
||||
var T2_parameters = T2.parameters;
|
||||
if (T1_parameters.length != T2_parameters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < T1_parameters.length; i++) {
|
||||
var T1_parameter = T1_parameters[i];
|
||||
var T2_parameter = T2_parameters[i];
|
||||
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
if (T1_parameter.parameterKind != T2_parameter.parameterKind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (T1_parameter.isNamed) {
|
||||
if (T1_parameter.name != T2_parameter.name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equal(T1_parameter.type, T2_parameter.type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitInterfaceType(InterfaceType T1, DartType T2) {
|
||||
if (T2 is InterfaceType &&
|
||||
T1.element == T2.element &&
|
||||
_compatibleNullability(T1, T2)) {
|
||||
var T1_typeArguments = T1.typeArguments;
|
||||
var T2_typeArguments = T2.typeArguments;
|
||||
if (T1_typeArguments.length == T2_typeArguments.length) {
|
||||
for (var i = 0; i < T1_typeArguments.length; i++) {
|
||||
var T1_typeArgument = T1_typeArguments[i];
|
||||
var T2_typeArgument = T2_typeArguments[i];
|
||||
if (!visit(T1_typeArgument, T2_typeArgument)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitNeverType(NeverTypeImpl T1, DartType T2) {
|
||||
// Note, that all types are normalized before this visitor.
|
||||
// So, `Never?` never happens, it is already `Null`.
|
||||
assert(T1.nullabilitySuffix != NullabilitySuffix.question);
|
||||
return T2 is NeverTypeImpl && _compatibleNullability(T1, T2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitTypeParameterType(TypeParameterType T1, DartType T2) {
|
||||
return T2 is TypeParameterType &&
|
||||
_compatibleNullability(T1, T2) &&
|
||||
T1.element == T2.element;
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitVoidType(VoidType T1, DartType T2) {
|
||||
return identical(T1, T2);
|
||||
}
|
||||
|
||||
bool _compatibleNullability(DartType T1, DartType T2) {
|
||||
var T1_nullability = T1.nullabilitySuffix;
|
||||
var T2_nullability = T2.nullabilitySuffix;
|
||||
return T1_nullability == T2_nullability ||
|
||||
T1_nullability == NullabilitySuffix.star &&
|
||||
T2_nullability == NullabilitySuffix.none ||
|
||||
T2_nullability == NullabilitySuffix.star &&
|
||||
T1_nullability == NullabilitySuffix.none;
|
||||
}
|
||||
|
||||
/// Determines if the two lists of type parameters are equal. If they are,
|
||||
/// returns a [_TypeParametersResult] indicating the substitutions necessary
|
||||
/// to demonstrate their equality. If they aren't, returns `null`.
|
||||
_TypeParametersResult _typeParameters(
|
||||
List<TypeParameterElement> T1_parameters,
|
||||
List<TypeParameterElement> T2_parameters,
|
||||
) {
|
||||
if (T1_parameters.length != T2_parameters.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var newParameters = <TypeParameterElementImpl>[];
|
||||
var newTypes = <TypeParameterType>[];
|
||||
for (var i = 0; i < T1_parameters.length; i++) {
|
||||
var name = T1_parameters[i].name;
|
||||
var newParameter = TypeParameterElementImpl.synthetic(name);
|
||||
newParameters.add(newParameter);
|
||||
|
||||
var newType = newParameter.instantiate(
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
newTypes.add(newType);
|
||||
}
|
||||
|
||||
var T1_substitution = Substitution.fromPairs(T1_parameters, newTypes);
|
||||
var T2_substitution = Substitution.fromPairs(T2_parameters, newTypes);
|
||||
for (var i = 0; i < T1_parameters.length; i++) {
|
||||
var T1_parameter = T1_parameters[i];
|
||||
var T2_parameter = T2_parameters[i];
|
||||
|
||||
var T1_bound = T1_parameter.bound;
|
||||
var T2_bound = T2_parameter.bound;
|
||||
if (T1_bound == null && T2_bound == null) {
|
||||
// OK, no bound.
|
||||
} else if (T1_bound != null && T2_bound != null) {
|
||||
T1_bound = T1_substitution.substituteType(T1_bound);
|
||||
T2_bound = T2_substitution.substituteType(T2_bound);
|
||||
if (!visit(T1_bound, T2_bound)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return _TypeParametersResult(T1_substitution, T2_substitution);
|
||||
}
|
||||
}
|
||||
|
||||
class _TypeParametersResult {
|
||||
final Substitution T1_substitution;
|
||||
final Substitution T2_substitution;
|
||||
|
||||
_TypeParametersResult(this.T1_substitution, this.T2_substitution);
|
||||
}
|
|
@ -62,3 +62,76 @@ class DartTypeVisitor<R> {
|
|||
throw UnimplementedError('(${type.runtimeType}) $type');
|
||||
}
|
||||
}
|
||||
|
||||
class DartTypeVisitor1<R, T> {
|
||||
const DartTypeVisitor1();
|
||||
|
||||
R defaultDartType(DartType type, T arg) => null;
|
||||
|
||||
R visitDynamicType(DynamicTypeImpl type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitFunctionType(FunctionType type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitFunctionTypeBuilder(FunctionTypeBuilder type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitInterfaceType(InterfaceType type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitNamedTypeBuilder(NamedTypeBuilder type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitNeverType(NeverTypeImpl type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitTypeParameterType(TypeParameterType type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitUnknownInferredType(UnknownInferredType type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
R visitVoidType(VoidType type, T arg) {
|
||||
return defaultDartType(type, arg);
|
||||
}
|
||||
|
||||
static R visit<R, T>(DartType type, DartTypeVisitor1<R, T> visitor, T arg) {
|
||||
if (type is NeverTypeImpl) {
|
||||
return visitor.visitNeverType(type, arg);
|
||||
}
|
||||
if (type is DynamicTypeImpl) {
|
||||
return visitor.visitDynamicType(type, arg);
|
||||
}
|
||||
if (type is FunctionType) {
|
||||
return visitor.visitFunctionType(type, arg);
|
||||
}
|
||||
if (type is FunctionTypeBuilder) {
|
||||
return visitor.visitFunctionTypeBuilder(type, arg);
|
||||
}
|
||||
if (type is InterfaceType) {
|
||||
return visitor.visitInterfaceType(type, arg);
|
||||
}
|
||||
if (type is NamedTypeBuilder) {
|
||||
return visitor.visitNamedTypeBuilder(type, arg);
|
||||
}
|
||||
if (type is TypeParameterType) {
|
||||
return visitor.visitTypeParameterType(type, arg);
|
||||
}
|
||||
if (type is UnknownInferredType) {
|
||||
return visitor.visitUnknownInferredType(type, arg);
|
||||
}
|
||||
if (type is VoidType) {
|
||||
return visitor.visitVoidType(type, arg);
|
||||
}
|
||||
throw UnimplementedError('(${type.runtimeType}) $type');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import 'package:analyzer/src/dart/element/element.dart';
|
|||
import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember;
|
||||
import 'package:analyzer/src/dart/element/normalize.dart';
|
||||
import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
|
||||
import 'package:analyzer/src/dart/element/runtime_type_equality.dart';
|
||||
import 'package:analyzer/src/dart/element/top_merge.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_algebra.dart';
|
||||
|
@ -1520,6 +1521,13 @@ class Dart2TypeSystem extends TypeSystem {
|
|||
return NormalizeHelper(this).normalize(T);
|
||||
}
|
||||
|
||||
/// Return `true` if runtime types [T1] and [T2] are equal.
|
||||
///
|
||||
/// nnbd/feature-specification.md#runtime-type-equality-operator
|
||||
bool runtimeTypesEqual(DartType T1, DartType T2) {
|
||||
return RuntimeTypeEqualityHelper(this).equal(T1, T2);
|
||||
}
|
||||
|
||||
@override
|
||||
DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
|
||||
DartType rightType, DartType currentType) {
|
||||
|
|
|
@ -14,6 +14,21 @@ import 'package:analyzer/src/generated/utilities_dart.dart';
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
mixin ElementsTypesMixin {
|
||||
InterfaceType get boolNone {
|
||||
var element = typeProvider.boolElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceType get boolQuestion {
|
||||
var element = typeProvider.boolElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
InterfaceType get boolStar {
|
||||
var element = typeProvider.boolElement;
|
||||
return interfaceTypeStar(element);
|
||||
}
|
||||
|
||||
InterfaceType get doubleNone {
|
||||
var element = typeProvider.doubleType.element;
|
||||
return interfaceTypeNone(element);
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
// 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:analyzer/dart/analysis/features.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/dart/element/type_provider.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart' show TypeSystemImpl;
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../../generated/elements_types_mixin.dart';
|
||||
import '../../../generated/test_analysis_context.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(RuntimeTypeEqualityTypeTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class RuntimeTypeEqualityTypeTest with ElementsTypesMixin {
|
||||
@override
|
||||
TypeProvider typeProvider;
|
||||
|
||||
TypeSystemImpl typeSystem;
|
||||
|
||||
FeatureSet get testFeatureSet {
|
||||
return FeatureSet.forTesting(
|
||||
additionalFeatures: [Feature.non_nullable],
|
||||
);
|
||||
}
|
||||
|
||||
void setUp() {
|
||||
var analysisContext = TestAnalysisContext(
|
||||
featureSet: testFeatureSet,
|
||||
);
|
||||
typeProvider = analysisContext.typeProviderNonNullableByDefault;
|
||||
typeSystem = analysisContext.typeSystemNonNullableByDefault;
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
_equal(dynamicNone, dynamicNone);
|
||||
_notEqual(dynamicNone, voidNone);
|
||||
_notEqual(dynamicNone, intNone);
|
||||
|
||||
_notEqual(dynamicNone, neverNone);
|
||||
_notEqual(dynamicNone, neverQuestion);
|
||||
_notEqual(dynamicNone, neverStar);
|
||||
}
|
||||
|
||||
test_functionType_parameters() {
|
||||
void check(
|
||||
ParameterElement T1_parameter,
|
||||
ParameterElement T2_parameter,
|
||||
bool expected,
|
||||
) {
|
||||
var T1 = functionTypeNone(
|
||||
returnType: voidNone,
|
||||
parameters: [T1_parameter],
|
||||
);
|
||||
var T2 = functionTypeNone(
|
||||
returnType: voidNone,
|
||||
parameters: [T2_parameter],
|
||||
);
|
||||
_check(T1, T2, expected);
|
||||
}
|
||||
|
||||
{
|
||||
void checkRequiredParameter(
|
||||
DartType T1_type,
|
||||
DartType T2_type,
|
||||
bool expected,
|
||||
) {
|
||||
check(
|
||||
requiredParameter(type: T1_type),
|
||||
requiredParameter(type: T2_type),
|
||||
expected,
|
||||
);
|
||||
}
|
||||
|
||||
checkRequiredParameter(intNone, intNone, true);
|
||||
checkRequiredParameter(intNone, intQuestion, false);
|
||||
checkRequiredParameter(intNone, intStar, true);
|
||||
|
||||
checkRequiredParameter(intQuestion, intNone, false);
|
||||
checkRequiredParameter(intQuestion, intQuestion, true);
|
||||
checkRequiredParameter(intQuestion, intStar, false);
|
||||
|
||||
checkRequiredParameter(intStar, intNone, true);
|
||||
checkRequiredParameter(intStar, intQuestion, false);
|
||||
checkRequiredParameter(intStar, intStar, true);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone, name: 'a'),
|
||||
requiredParameter(type: intNone, name: 'b'),
|
||||
true,
|
||||
);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone),
|
||||
positionalParameter(type: intNone),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone),
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone),
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
true,
|
||||
);
|
||||
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: boolNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: intNone, name: 'b'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
true,
|
||||
);
|
||||
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: boolNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: intNone, name: 'b'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test_functionType_returnType() {
|
||||
void check(
|
||||
DartType T1_returnType,
|
||||
DartType T2_returnType,
|
||||
bool expected,
|
||||
) {
|
||||
var T1 = functionTypeNone(
|
||||
returnType: T1_returnType,
|
||||
);
|
||||
var T2 = functionTypeNone(
|
||||
returnType: T2_returnType,
|
||||
);
|
||||
_check(T1, T2, expected);
|
||||
}
|
||||
|
||||
check(intNone, intNone, true);
|
||||
check(intNone, intQuestion, false);
|
||||
check(intNone, intStar, true);
|
||||
}
|
||||
|
||||
test_functionType_typeParameters() {
|
||||
{
|
||||
var T1_T = typeParameter('T', bound: numNone);
|
||||
_check(
|
||||
functionTypeNone(
|
||||
typeFormals: [T1_T],
|
||||
returnType: voidNone,
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var T1_T = typeParameter('T', bound: numNone);
|
||||
var T2_U = typeParameter('U');
|
||||
_check(
|
||||
functionTypeNone(
|
||||
typeFormals: [T1_T],
|
||||
returnType: voidNone,
|
||||
),
|
||||
functionTypeNone(
|
||||
typeFormals: [T2_U],
|
||||
returnType: voidNone,
|
||||
),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var T1_T = typeParameter('T');
|
||||
var T2_U = typeParameter('U');
|
||||
_check(
|
||||
functionTypeNone(
|
||||
typeFormals: [T1_T],
|
||||
returnType: typeParameterTypeNone(T1_T),
|
||||
parameters: [
|
||||
requiredParameter(
|
||||
type: typeParameterTypeNone(T1_T),
|
||||
)
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
typeFormals: [T2_U],
|
||||
returnType: typeParameterTypeNone(T2_U),
|
||||
parameters: [
|
||||
requiredParameter(
|
||||
type: typeParameterTypeNone(T2_U),
|
||||
)
|
||||
],
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_notEqual(intNone, boolNone);
|
||||
|
||||
_equal(intNone, intNone);
|
||||
_notEqual(intNone, intQuestion);
|
||||
_equal(intNone, intStar);
|
||||
|
||||
_notEqual(intQuestion, intNone);
|
||||
_equal(intQuestion, intQuestion);
|
||||
_notEqual(intQuestion, intStar);
|
||||
|
||||
_equal(intStar, intNone);
|
||||
_notEqual(intStar, intQuestion);
|
||||
_equal(intStar, intStar);
|
||||
}
|
||||
|
||||
test_interfaceType_typeArguments() {
|
||||
void _equal(DartType T1, DartType T2) {
|
||||
this._equal(listNone(T1), listNone(T2));
|
||||
}
|
||||
|
||||
void _notEqual(DartType T1, DartType T2) {
|
||||
this._notEqual(listNone(T1), listNone(T2));
|
||||
}
|
||||
|
||||
_notEqual(intNone, boolNone);
|
||||
|
||||
_equal(intNone, intNone);
|
||||
_notEqual(intNone, intQuestion);
|
||||
_equal(intNone, intStar);
|
||||
|
||||
_notEqual(intQuestion, intNone);
|
||||
_equal(intQuestion, intQuestion);
|
||||
_notEqual(intQuestion, intStar);
|
||||
|
||||
_equal(intStar, intNone);
|
||||
_notEqual(intStar, intQuestion);
|
||||
_equal(intStar, intStar);
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_equal(neverNone, neverNone);
|
||||
_notEqual(neverNone, neverQuestion);
|
||||
_equal(neverNone, neverStar);
|
||||
_notEqual(neverNone, intNone);
|
||||
|
||||
_notEqual(neverQuestion, neverNone);
|
||||
_equal(neverQuestion, neverQuestion);
|
||||
_notEqual(neverQuestion, neverStar);
|
||||
_notEqual(neverQuestion, intNone);
|
||||
_equal(neverQuestion, nullNone);
|
||||
|
||||
_equal(neverStar, neverNone);
|
||||
_notEqual(neverStar, neverQuestion);
|
||||
_equal(neverStar, neverStar);
|
||||
_notEqual(neverStar, intNone);
|
||||
}
|
||||
|
||||
test_norm() {
|
||||
_equal(futureOrNone(objectNone), objectNone);
|
||||
_equal(futureOrNone(neverNone), futureNone(neverNone));
|
||||
_equal(neverQuestion, nullNone);
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_equal(voidNone, voidNone);
|
||||
_notEqual(voidNone, dynamicNone);
|
||||
_notEqual(voidNone, intNone);
|
||||
|
||||
_notEqual(voidNone, neverNone);
|
||||
_notEqual(voidNone, neverQuestion);
|
||||
_notEqual(voidNone, neverStar);
|
||||
}
|
||||
|
||||
void _check(DartType T1, DartType T2, bool expected) {
|
||||
bool result;
|
||||
|
||||
result = typeSystem.runtimeTypesEqual(T1, T2);
|
||||
if (result != expected) {
|
||||
fail('''
|
||||
Expected ${expected ? 'equal' : 'not equal'}.
|
||||
T1: ${_typeString(T1)}
|
||||
T2: ${_typeString(T2)}
|
||||
''');
|
||||
}
|
||||
|
||||
result = typeSystem.runtimeTypesEqual(T2, T1);
|
||||
if (result != expected) {
|
||||
fail('''
|
||||
Expected ${expected ? 'equal' : 'not equal'}.
|
||||
T1: ${_typeString(T1)}
|
||||
T2: ${_typeString(T2)}
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
||||
void _equal(DartType T1, DartType T2) {
|
||||
_check(T1, T2, true);
|
||||
}
|
||||
|
||||
void _notEqual(DartType T1, DartType T2) {
|
||||
_check(T1, T2, false);
|
||||
}
|
||||
|
||||
String _typeString(TypeImpl type) {
|
||||
if (type == null) return null;
|
||||
return type.getDisplayString(withNullability: true);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import 'least_upper_bound_helper_test.dart' as least_upper_bound_helper;
|
|||
import 'normalize_type_test.dart' as normalize_type;
|
||||
import 'nullability_eliminator_test.dart' as nullability_eliminator;
|
||||
import 'nullable_test.dart' as nullable;
|
||||
import 'runtime_type_equality_test.dart' as runtime_type_equality;
|
||||
import 'subtype_test.dart' as subtype;
|
||||
import 'top_merge_test.dart' as top_merge;
|
||||
import 'type_algebra_test.dart' as type_algebra;
|
||||
|
@ -27,6 +28,7 @@ main() {
|
|||
normalize_type.main();
|
||||
nullability_eliminator.main();
|
||||
nullable.main();
|
||||
runtime_type_equality.main();
|
||||
subtype.main();
|
||||
top_merge.main();
|
||||
type_algebra.main();
|
||||
|
|
Loading…
Reference in a new issue