blob: 76c68532c53249531f49ba5a467cc3e2da7f1196 [file] [log] [blame] [edit]
// Copyright (c) 2022, 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:kernel/type_algebra.dart';
import '../ast.dart';
import 'replacement_visitor.dart';
/// Replaces all occurrences of [TypedefType] in [type] with the corresponding
/// unaliased type.
///
/// If [legacyEraseAliases] is `true`, the unaliased types will be legacy
/// erased. This used when the [TypedefType] was used in a legacy library.
DartType unalias(DartType type) {
return rawUnalias(type) ?? type;
}
/// Replaces all occurrences of [TypedefType] in [types] with the corresponding
/// unaliased types.
///
/// If [legacyEraseAliases] is `true`, the unaliased types will be legacy
/// erased. This used when the [TypedefType] was used in a legacy library.
List<DartType>? unaliasTypes(List<DartType>? types) {
if (types == null) return null;
return rawUnaliasTypes(types) ?? types;
}
/// Replaces all occurrences of [TypedefType] in [type] with the corresponding
/// unaliased type, or returns `null` if no [TypedefType]s were found.
///
/// If [legacyEraseAliases] is `true`, the unaliased types will be legacy
/// erased. This used when the [TypedefType] was used in a legacy library.
DartType? rawUnalias(DartType type) {
return type.accept1(const _Unalias(), Variance.covariant);
}
/// Replaces all occurrences of [TypedefType] in [types] with the corresponding
/// unaliased types, or returns `null` if no [TypedefType]s were found.
///
/// If [legacyEraseAliases] is `true`, the unaliased types will be legacy
/// erased. This used when the [TypedefType] was used in a legacy library.
List<DartType>? rawUnaliasTypes(List<DartType> types) {
List<DartType>? newTypes;
for (int i = 0; i < types.length; i++) {
DartType typeArgument = types[i];
DartType? newTypeArgument = rawUnalias(typeArgument);
if (newTypeArgument != null) {
newTypes ??= types.toList(growable: false);
newTypes[i] = newTypeArgument;
}
}
return newTypes;
}
/// Visitor that replaces all occurrences of [TypedefType] with the
/// corresponding unaliased type, or returns `null` if no type was replaced.
///
/// If [legacyEraseAliases] is `true`, the unaliased types will be legacy
/// erased. This used when the [TypedefType] was used in a legacy library.
class _Unalias extends ReplacementVisitor {
const _Unalias();
@override
DartType visitTypedefType(TypedefType node, Variance variance) {
DartType result;
if (node.typeArguments.isNotEmpty) {
List<DartType>? newTypeArguments = null;
for (int i = 0; i < node.typeArguments.length; i++) {
DartType? substitution = node.typeArguments[i].accept1(this, variance);
if (substitution != null) {
newTypeArguments ??= node.typeArguments.toList(growable: false);
newTypeArguments[i] = substitution;
}
}
if (newTypeArguments != null) {
result = new TypedefType(
node.typedefNode, node.nullability, newTypeArguments)
.unalias;
} else {
result = node.unalias;
}
} else {
result = node.unalias;
}
result = result.withDeclaredNullability(uniteNullabilities(
node.declaredNullability, result.declaredNullability));
return result;
}
}