mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:20:31 +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'
|
import '../js_ast/source_map_printer.dart'
|
||||||
show NodeEnd, NodeSpan, HoverComment, continueSourceMap;
|
show NodeEnd, NodeSpan, HoverComment, continueSourceMap;
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
|
import 'future_or_normalizer.dart';
|
||||||
import 'js_interop.dart';
|
import 'js_interop.dart';
|
||||||
import 'js_typerep.dart';
|
import 'js_typerep.dart';
|
||||||
import 'kernel_helpers.dart';
|
import 'kernel_helpers.dart';
|
||||||
|
@ -939,7 +940,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
||||||
}
|
}
|
||||||
return _emitInterfaceType(t, emitNullability: emitNullability);
|
return _emitInterfaceType(t, emitNullability: emitNullability);
|
||||||
} else if (t is FutureOrType) {
|
} else if (t is FutureOrType) {
|
||||||
var normalizedType = _normalizeFutureOr(t);
|
var normalizedType = normalizeFutureOr(t, _coreTypes);
|
||||||
if (normalizedType is FutureOrType) {
|
if (normalizedType is FutureOrType) {
|
||||||
_declareBeforeUse(_coreTypes.deprecatedFutureOrClass);
|
_declareBeforeUse(_coreTypes.deprecatedFutureOrClass);
|
||||||
var typeRep = _emitFutureOrTypeWithArgument(
|
var typeRep = _emitFutureOrTypeWithArgument(
|
||||||
|
@ -2911,64 +2912,6 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
||||||
? visitNullType(const NullType())
|
? visitNullType(const NullType())
|
||||||
: _emitNullabilityWrapper(runtimeCall('Never'), type.nullability);
|
: _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
|
@override
|
||||||
js_ast.Expression visitInterfaceType(InterfaceType type) =>
|
js_ast.Expression visitInterfaceType(InterfaceType type) =>
|
||||||
_emitInterfaceType(type);
|
_emitInterfaceType(type);
|
||||||
|
@ -2979,7 +2922,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
js_ast.Expression visitFutureOrType(FutureOrType type) {
|
js_ast.Expression visitFutureOrType(FutureOrType type) {
|
||||||
var normalizedType = _normalizeFutureOr(type);
|
var normalizedType = normalizeFutureOr(type, _coreTypes);
|
||||||
return normalizedType is FutureOrType
|
return normalizedType is FutureOrType
|
||||||
? _emitFutureOrType(normalizedType)
|
? _emitFutureOrType(normalizedType)
|
||||||
: normalizedType.accept(this);
|
: 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