mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
[ddc] Move FutureOr normalization to its own visitor
Will make it easier to reuse the normalization when compiling with the new runtime type representation. Change-Id: Ie767a2b676950205b0b50eadac305c29914433f2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/247420 Reviewed-by: Srujan Gaddam <srujzs@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
parent
f3daca2ef6
commit
624dd76b6f
2 changed files with 94 additions and 60 deletions
|
@ -32,6 +32,7 @@ import '../js_ast/js_ast.dart' show ModuleItem, js;
|
|||
import '../js_ast/source_map_printer.dart'
|
||||
show NodeEnd, NodeSpan, HoverComment, continueSourceMap;
|
||||
import 'constants.dart';
|
||||
import 'future_or_normalizer.dart';
|
||||
import 'js_interop.dart';
|
||||
import 'js_typerep.dart';
|
||||
import 'kernel_helpers.dart';
|
||||
|
@ -939,7 +940,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
}
|
||||
return _emitInterfaceType(t, emitNullability: emitNullability);
|
||||
} else if (t is FutureOrType) {
|
||||
var normalizedType = _normalizeFutureOr(t);
|
||||
var normalizedType = normalizeFutureOr(t, _coreTypes);
|
||||
if (normalizedType is FutureOrType) {
|
||||
_declareBeforeUse(_coreTypes.deprecatedFutureOrClass);
|
||||
var typeRep = _emitFutureOrTypeWithArgument(
|
||||
|
@ -2911,64 +2912,6 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
? visitNullType(const NullType())
|
||||
: _emitNullabilityWrapper(runtimeCall('Never'), type.nullability);
|
||||
|
||||
/// Normalizes `FutureOr` types.
|
||||
///
|
||||
/// Any changes to the normalization logic here should be mirrored in the
|
||||
/// classes.dart runtime library method named `normalizeFutureOr`.
|
||||
DartType _normalizeFutureOr(FutureOrType futureOr) {
|
||||
var typeArgument = futureOr.typeArgument;
|
||||
if (typeArgument is DynamicType) {
|
||||
// FutureOr<dynamic> --> dynamic
|
||||
return typeArgument;
|
||||
}
|
||||
if (typeArgument is VoidType) {
|
||||
// FutureOr<void> --> void
|
||||
return typeArgument;
|
||||
}
|
||||
|
||||
if (typeArgument is InterfaceType &&
|
||||
typeArgument.classNode == _coreTypes.objectClass) {
|
||||
// Normalize FutureOr of Object, Object?, Object*.
|
||||
var nullable = futureOr.nullability == Nullability.nullable ||
|
||||
typeArgument.nullability == Nullability.nullable;
|
||||
var legacy = futureOr.nullability == Nullability.legacy ||
|
||||
typeArgument.nullability == Nullability.legacy;
|
||||
var nullability = nullable
|
||||
? Nullability.nullable
|
||||
: legacy
|
||||
? Nullability.legacy
|
||||
: Nullability.nonNullable;
|
||||
return typeArgument.withDeclaredNullability(nullability);
|
||||
} else if (typeArgument is NeverType) {
|
||||
// FutureOr<Never> --> Future<Never>
|
||||
return InterfaceType(
|
||||
_coreTypes.futureClass, futureOr.nullability, [typeArgument]);
|
||||
} else if (typeArgument is NullType) {
|
||||
// FutureOr<Null> --> Future<Null>?
|
||||
return InterfaceType(
|
||||
_coreTypes.futureClass, Nullability.nullable, [typeArgument]);
|
||||
} else if (futureOr.declaredNullability == Nullability.nullable &&
|
||||
typeArgument.nullability == Nullability.nullable) {
|
||||
// FutureOr<T?>? --> FutureOr<T?>
|
||||
return futureOr.withDeclaredNullability(Nullability.nonNullable);
|
||||
}
|
||||
// The following is not part of the normalization spec but this is a
|
||||
// convenient place to perform this change of nullability consistently. This
|
||||
// only applies at compile-time and is not needed in the runtime version of
|
||||
// the FutureOr normalization.
|
||||
// FutureOr<T%>% --> FutureOr<T%>
|
||||
//
|
||||
// If the type argument has undetermined nullability the CFE propagates
|
||||
// it to the FutureOr type as well. In this case we can represent the
|
||||
// FutureOr type without any nullability wrappers and rely on the runtime to
|
||||
// handle the nullability of the instantiated type appropriately.
|
||||
if (futureOr.nullability == Nullability.undetermined &&
|
||||
typeArgument.nullability == Nullability.undetermined) {
|
||||
return futureOr.withDeclaredNullability(Nullability.nonNullable);
|
||||
}
|
||||
return futureOr;
|
||||
}
|
||||
|
||||
@override
|
||||
js_ast.Expression visitInterfaceType(InterfaceType type) =>
|
||||
_emitInterfaceType(type);
|
||||
|
@ -2979,7 +2922,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
|
||||
@override
|
||||
js_ast.Expression visitFutureOrType(FutureOrType type) {
|
||||
var normalizedType = _normalizeFutureOr(type);
|
||||
var normalizedType = normalizeFutureOr(type, _coreTypes);
|
||||
return normalizedType is FutureOrType
|
||||
? _emitFutureOrType(normalizedType)
|
||||
: normalizedType.accept(this);
|
||||
|
|
91
pkg/dev_compiler/lib/src/kernel/future_or_normalizer.dart
Normal file
91
pkg/dev_compiler/lib/src/kernel/future_or_normalizer.dart
Normal file
|
@ -0,0 +1,91 @@
|
|||
// 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/ast.dart';
|
||||
import 'package:kernel/core_types.dart';
|
||||
import 'package:kernel/kernel.dart';
|
||||
import 'package:kernel/src/replacement_visitor.dart';
|
||||
|
||||
/// Normalizes all `FutureOr` types found in [type].
|
||||
DartType normalizeFutureOr(DartType type, CoreTypes coreTypes) =>
|
||||
type.accept1(_FutureOrNormalizer.instance(coreTypes), Variance.unrelated) ??
|
||||
type;
|
||||
|
||||
/// Visit methods returns a normalized version of `FutureOr` types or `null` if
|
||||
/// no normalization was applied.
|
||||
///
|
||||
/// The `variance` parameters in the visit methods are unused in this type
|
||||
/// replacement.
|
||||
///
|
||||
/// `FutureOr` types are normalized per the spec:
|
||||
/// https://github.com/dart-lang/language/blob/master/resources/type-system/normalization.md
|
||||
///
|
||||
/// Any changes to the normalization logic here should be mirrored in the
|
||||
/// classes.dart runtime library method named `normalizeFutureOr`.
|
||||
class _FutureOrNormalizer extends ReplacementVisitor {
|
||||
final CoreTypes _coreTypes;
|
||||
|
||||
static _FutureOrNormalizer? _instance;
|
||||
|
||||
_FutureOrNormalizer._(this._coreTypes);
|
||||
|
||||
factory _FutureOrNormalizer.instance(CoreTypes coreTypes) =>
|
||||
_instance ?? (_instance = _FutureOrNormalizer._(coreTypes));
|
||||
|
||||
@override
|
||||
DartType? visitFutureOrType(FutureOrType futureOr, int variance) {
|
||||
var normalizedTypeArg = futureOr.typeArgument.accept1(this, variance);
|
||||
var typeArgument = normalizedTypeArg ?? futureOr.typeArgument;
|
||||
if (typeArgument is DynamicType) {
|
||||
// FutureOr<dynamic> --> dynamic
|
||||
return typeArgument;
|
||||
}
|
||||
if (typeArgument is VoidType) {
|
||||
// FutureOr<void> --> void
|
||||
return typeArgument;
|
||||
}
|
||||
|
||||
if (typeArgument is InterfaceType &&
|
||||
typeArgument.classNode == _coreTypes.objectClass) {
|
||||
// Normalize FutureOr of Object, Object?, Object*.
|
||||
var nullable = futureOr.nullability == Nullability.nullable ||
|
||||
typeArgument.nullability == Nullability.nullable;
|
||||
var legacy = futureOr.nullability == Nullability.legacy ||
|
||||
typeArgument.nullability == Nullability.legacy;
|
||||
var nullability = nullable
|
||||
? Nullability.nullable
|
||||
: legacy
|
||||
? Nullability.legacy
|
||||
: Nullability.nonNullable;
|
||||
return typeArgument.withDeclaredNullability(nullability);
|
||||
} else if (typeArgument is NeverType) {
|
||||
// FutureOr<Never> --> Future<Never>
|
||||
return InterfaceType(
|
||||
_coreTypes.futureClass, futureOr.nullability, [typeArgument]);
|
||||
} else if (typeArgument is NullType) {
|
||||
// FutureOr<Null> --> Future<Null>?
|
||||
return InterfaceType(
|
||||
_coreTypes.futureClass, Nullability.nullable, [typeArgument]);
|
||||
} else if (futureOr.declaredNullability == Nullability.nullable &&
|
||||
typeArgument.nullability == Nullability.nullable) {
|
||||
// FutureOr<T?>? --> FutureOr<T?>
|
||||
return futureOr.withDeclaredNullability(Nullability.nonNullable);
|
||||
}
|
||||
// The following is not part of the normalization spec but this is a
|
||||
// convenient place to perform this change of nullability consistently. This
|
||||
// only applies at compile-time and is not needed in the runtime version of
|
||||
// the FutureOr normalization.
|
||||
// FutureOr<T%>% --> FutureOr<T%>
|
||||
//
|
||||
// If the type argument has undetermined nullability the CFE propagates
|
||||
// it to the FutureOr type as well. In this case we can represent the
|
||||
// FutureOr type without any nullability wrappers and rely on the runtime to
|
||||
// handle the nullability of the instantiated type appropriately.
|
||||
if (futureOr.declaredNullability == Nullability.undetermined &&
|
||||
typeArgument.declaredNullability == Nullability.undetermined) {
|
||||
return futureOr.withDeclaredNullability(Nullability.nonNullable);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue