blob: f0c5b4e71c5917dc7b6c1835f0a64dcac5bcd339 [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.md file.
import '../ast.dart' hide MapEntry;
import '../core_types.dart';
import 'merge_visitor.dart';
/// Returns the NNBD_TOP_MERGE of [a] and [b]. If [a] and [b] have no defined
/// NNBD_TOP_MERGE `null` is returned.
Supertype nnbdTopMergeSupertype(CoreTypes coreTypes, Supertype a, Supertype b) {
assert(a.classNode == b.classNode);
if (a.typeArguments.isEmpty) {
return a;
}
List<DartType> newTypeArguments = new List<DartType>(a.typeArguments.length);
for (int i = 0; i < a.typeArguments.length; i++) {
DartType newTypeArgument =
nnbdTopMerge(coreTypes, a.typeArguments[i], b.typeArguments[i]);
if (newTypeArgument == null) return null;
newTypeArguments[i] = newTypeArgument;
}
return new Supertype(a.classNode, newTypeArguments);
}
/// Returns the NNBD_TOP_MERGE of [a] and [b]. If [a] and [b] have no defined
/// NNBD_TOP_MERGE `null` is returned.
DartType nnbdTopMerge(CoreTypes coreTypes, DartType a, DartType b) {
if (a == b) return a;
return a.accept1(new NnbdTopMergeVisitor(coreTypes), b);
}
class NnbdTopMergeVisitor extends MergeVisitor {
final CoreTypes coreTypes;
NnbdTopMergeVisitor(this.coreTypes);
@override
Nullability mergeNullability(Nullability a, Nullability b) {
if (a == b) {
return a;
} else if (a == Nullability.legacy) {
return b;
} else if (b == Nullability.legacy) {
return a;
}
return null;
}
@override
DartType visitInterfaceType(InterfaceType a, DartType b) {
if (a == coreTypes.objectNullableRawType) {
if (b is DynamicType) {
// NNBD_TOP_MERGE(Object?, dynamic) = Object?
return coreTypes.objectNullableRawType;
} else if (b is VoidType) {
// NNBD_TOP_MERGE(Object?, void) = Object?
return coreTypes.objectNullableRawType;
} else if (b == coreTypes.objectNullableRawType) {
// NNBD_TOP_MERGE(Object?, Object?) = Object?
return coreTypes.objectNullableRawType;
}
} else if (a == coreTypes.objectLegacyRawType) {
if (b is DynamicType) {
// NNBD_TOP_MERGE(Object*, dynamic) = Object?
return coreTypes.objectNullableRawType;
} else if (b is VoidType) {
// NNBD_TOP_MERGE(Object*, void) = Object?
return coreTypes.objectNullableRawType;
}
} else if (a == coreTypes.nullType &&
b is NeverType &&
b.nullability == Nullability.legacy) {
// NNBD_TOP_MERGE(Null, Never*) = Null
return coreTypes.nullType;
}
return super.visitInterfaceType(a, b);
}
@override
DartType visitVoidType(VoidType a, DartType b) {
if (b is DynamicType) {
// NNBD_TOP_MERGE(void, dynamic) = Object?
return coreTypes.objectNullableRawType;
} else if (b is VoidType) {
// NNBD_TOP_MERGE(void, void) = void
return const VoidType();
} else if (b == coreTypes.objectNullableRawType) {
// NNBD_TOP_MERGE(void, Object?) = Object?
return coreTypes.objectNullableRawType;
} else if (b == coreTypes.objectLegacyRawType) {
// NNBD_TOP_MERGE(void, Object*) = Object?
return coreTypes.objectNullableRawType;
}
return null;
}
@override
DartType visitDynamicType(DynamicType a, DartType b) {
if (b is DynamicType) {
// NNBD_TOP_MERGE(dynamic, dynamic) = dynamic
return const DynamicType();
} else if (b is VoidType) {
// NNBD_TOP_MERGE(dynamic, void) = Object?
return coreTypes.objectNullableRawType;
} else if (b == coreTypes.objectNullableRawType) {
// NNBD_TOP_MERGE(dynamic, Object?) = Object?
return coreTypes.objectNullableRawType;
} else if (b == coreTypes.objectLegacyRawType) {
// NNBD_TOP_MERGE(dynamic, Object*) = Object?
return coreTypes.objectNullableRawType;
}
return null;
}
@override
DartType visitNeverType(NeverType a, DartType b) {
if (a.nullability == Nullability.legacy && b == coreTypes.nullType) {
// NNBD_TOP_MERGE(Never*, Null) = Null
return coreTypes.nullType;
}
return super.visitNeverType(a, b);
}
}