Version 2.13.1
* Cherry-pick d9f03e9580243502b589c2577c4fd84bbb603cfd to stable
* Cherry-pick 5b64d1233b1d8c12df6ec320a237b89ee738b5f6 to stable
* Cherry-pick ec48e8f323d68717cd3fed94abd85d4f82ea1ce7 to stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 844bbba..2575e61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 2.13.1 - 2021-05-25
+
+This is a patch release that fixes:
+
+* incorrect behavior in CastMap (issue [#45473][]).
+* missing nullability from recursive type hierarchies in DDC (issue [#45767][]).
+
+[#45473]: https://github.com/dart-lang/sdk/issues/45473
+[#45767]: https://github.com/dart-lang/sdk/issues/45767
+
## 2.13.0 - 2021-05-18
### Language
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index a01a3b9..84bfd17 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -94,6 +94,9 @@
/// The class that is emitting its signature information, otherwise null.
Class _classEmittingSignatures;
+ /// True when a class is emitting a deferred class hierarchy.
+ bool _emittingDeferredType = false;
+
/// The current element being loaded.
/// We can use this to determine if we're loading top-level code or not:
///
@@ -859,22 +862,38 @@
return;
}
- js_ast.Expression emitDeferredType(DartType t) {
- assert(isKnownDartTypeImplementor(t));
- if (t is InterfaceType) {
- _declareBeforeUse(t.classNode);
- if (t.typeArguments.isNotEmpty) {
- return _emitGenericClassType(
- t, t.typeArguments.map(emitDeferredType));
+ js_ast.Expression emitDeferredType(DartType t,
+ {bool emitNullability = true}) {
+ js_ast.Expression _emitDeferredType(DartType t,
+ {bool emitNullability = true}) {
+ if (t is InterfaceType) {
+ _declareBeforeUse(t.classNode);
+ if (t.typeArguments.isNotEmpty) {
+ var typeRep = _emitGenericClassType(
+ t, t.typeArguments.map(_emitDeferredType));
+ return emitNullability
+ ? _emitNullabilityWrapper(typeRep, t.declaredNullability)
+ : typeRep;
+ }
+ return _emitInterfaceType(t, emitNullability: emitNullability);
+ } else if (t is FutureOrType) {
+ _declareBeforeUse(_coreTypes.deprecatedFutureOrClass);
+ // TODO(45870) Add nullability wrappers to FutureOr.
+ return _emitFutureOrTypeWithArgument(
+ _emitDeferredType(t.typeArgument));
+ } else if (t is TypeParameterType) {
+ return _emitTypeParameterType(t, emitNullability: emitNullability);
}
- return _emitInterfaceType(t, emitNullability: false);
- } else if (t is FutureOrType) {
- _declareBeforeUse(_coreTypes.deprecatedFutureOrClass);
- return _emitFutureOrTypeWithArgument(emitDeferredType(t.typeArgument));
- } else if (t is TypeParameterType) {
- return _emitTypeParameterType(t, emitNullability: false);
+ return _emitType(t);
}
- return _emitType(t);
+
+ assert(isKnownDartTypeImplementor(t));
+ var savedEmittingDeferredType = _emittingDeferredType;
+ _emittingDeferredType = true;
+ var deferredClassRep =
+ _emitDeferredType(t, emitNullability: emitNullability);
+ _emittingDeferredType = savedEmittingDeferredType;
+ return deferredClassRep;
}
bool shouldDefer(InterfaceType t) {
@@ -921,7 +940,8 @@
js_ast.Expression getBaseClass(int count) {
var base = emitDeferredType(
- c.getThisType(_coreTypes, c.enclosingLibrary.nonNullable));
+ c.getThisType(_coreTypes, c.enclosingLibrary.nonNullable),
+ emitNullability: false);
while (--count >= 0) {
base = js.call('#.__proto__', [base]);
}
@@ -995,7 +1015,7 @@
var originalSupertype = supertype;
deferredSupertypes.add(() => runtimeStatement('setBaseClass(#, #)', [
getBaseClass(isMixinAliasClass(c) ? 0 : mixinApplications.length),
- emitDeferredType(originalSupertype),
+ emitDeferredType(originalSupertype, emitNullability: false),
]));
// Refers to 'supertype' without type parameters. We remove these from
// the 'extends' clause for generics for cyclic dependencies and append
@@ -1015,7 +1035,9 @@
var m = c.mixedInType.asInterfaceType;
var deferMixin = shouldDefer(m);
- var mixinClass = deferMixin ? emitDeferredType(m) : emitClassRef(m);
+ var mixinClass = deferMixin
+ ? emitDeferredType(m, emitNullability: false)
+ : emitClassRef(m);
var classExpr = deferMixin ? getBaseClass(0) : className;
var mixinApplication =
@@ -1087,7 +1109,7 @@
if (shouldDefer(mixinType)) {
deferredSupertypes.add(() => runtimeStatement('applyMixin(#, #)', [
getBaseClass(mixinApplications.length - i),
- emitDeferredType(mixinType)
+ emitDeferredType(mixinType, emitNullability: false)
]));
} else {
body.add(runtimeStatement(
@@ -2909,7 +2931,9 @@
_currentClass != null && identical(_currentClass, _classEmittingExtends);
bool get _cacheTypes =>
- !_emittingClassExtends && !_emittingClassSignatures ||
+ !_emittingDeferredType &&
+ !_emittingClassExtends &&
+ !_emittingClassSignatures ||
_currentFunction != null;
js_ast.Expression _emitGenericClassType(
diff --git a/sdk/lib/internal/cast.dart b/sdk/lib/internal/cast.dart
index d99b687..e3e0dae 100644
--- a/sdk/lib/internal/cast.dart
+++ b/sdk/lib/internal/cast.dart
@@ -277,7 +277,7 @@
_source.addAll(new CastMap<K, V, SK, SV>(other));
}
- V remove(Object? key) => _source.remove(key) as V;
+ V? remove(Object? key) => _source.remove(key) as V?;
void clear() {
_source.clear();
diff --git a/tests/corelib/regress_45473_test.dart b/tests/corelib/regress_45473_test.dart
new file mode 100644
index 0000000..4469e13
--- /dev/null
+++ b/tests/corelib/regress_45473_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, 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:expect/expect.dart";
+
+void main() {
+ var map = <String, dynamic>{"a": null};
+ var castMap = map.cast<String, Object>();
+ // Should return `null`, not throw.
+ Expect.isNull(castMap.remove("b"));
+ Expect.isNull(castMap.remove("a"));
+}
diff --git a/tests/language/generic/regress_45767_test.dart b/tests/language/generic/regress_45767_test.dart
new file mode 100644
index 0000000..953c966
--- /dev/null
+++ b/tests/language/generic/regress_45767_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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 'dart:async';
+
+import 'package:expect/expect.dart';
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45767.
+
+class I<T> {}
+
+class F<E extends F<E>> extends I<E> {}
+
+// Extending F forces DDC to defer the superclass and trigger the bug
+class A<T> extends F<A<Object?>> {}
+
+class B<T> extends F<B<T?>> {}
+
+void main() {
+ Expect.isTrue(A<bool>() is I<A<Object?>>);
+ Expect.equals(!hasSoundNullSafety, A<bool>() is I<A<Object>>);
+ Expect.isTrue(B<bool>() is I<B<bool?>>);
+ Expect.equals(!hasSoundNullSafety, B<bool>() is I<B<bool>>);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 46d7061..78eab55 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
CHANNEL stable
MAJOR 2
MINOR 13
-PATCH 0
+PATCH 1
PRERELEASE 0
PRERELEASE_PATCH 0
\ No newline at end of file