Version 2.17.0-277.0.dev
Merge commit '8178fdea4046837c4855e06d67c373543b9ffcbc' into 'dev'
diff --git a/DEPS b/DEPS
index a5a4e52..db1a550 100644
--- a/DEPS
+++ b/DEPS
@@ -110,7 +110,7 @@
"dart_style_rev": "d7b73536a8079331c888b7da539b80e6825270ea",
"dartdoc_rev" : "334072b0cad436c05f6bcecf8a1a59f2f0809b84",
- "devtools_rev" : "2a707ca56c1a9d5eeef212c28c573548a051fdd2",
+ "devtools_rev" : "8c525828ba33029ed664bf8ea2829b6e5370535f",
"ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
"fixnum_rev": "848341f061359ef7ddc0cad472c2ecbb036b28ac",
"file_rev": "1ebc38852ffed24b564910317982298b56c2cedd",
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 527f2fa..0ec9bc0 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -31,8 +31,7 @@
import '../universe/feature.dart';
import '../universe/selector.dart';
import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse;
-import '../universe/world_impact.dart'
- show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
+import '../universe/world_impact.dart' show WorldImpact, WorldImpactBuilderImpl;
import '../util/enumset.dart';
import '../util/util.dart';
import '../world.dart';
@@ -201,15 +200,6 @@
sink.end(tag);
}
- @override
- void apply(WorldImpactVisitor visitor) {
- staticUses.forEach((StaticUse use) => visitor.visitStaticUse(member, use));
- dynamicUses.forEach((DynamicUse use) => visitor.visitDynamicUse);
- typeUses.forEach((TypeUse use) => visitor.visitTypeUse(member, use));
- constantUses
- .forEach((ConstantUse use) => visitor.visitConstantUse(member, use));
- }
-
void registerTypeVariableBoundsSubtypeCheck(
DartType subtype, DartType supertype) {
_typeVariableBoundsSubtypeChecks ??= {};
diff --git a/pkg/compiler/lib/src/deferred_load/entity_data_info.dart b/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
index 6f6c33a..7c0c07d 100644
--- a/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
+++ b/pkg/compiler/lib/src/deferred_load/entity_data_info.dart
@@ -19,7 +19,7 @@
import '../kernel/element_map.dart';
import '../kernel/kernel_world.dart';
import '../universe/use.dart';
-import '../universe/world_impact.dart' show WorldImpact, WorldImpactVisitorImpl;
+import '../universe/world_impact.dart' show WorldImpact;
/// [EntityDataInfo] is meta data about [EntityData] for a given compilation
/// [Entity].
@@ -239,16 +239,13 @@
/// Extract any dependencies that are known from the impact of [element].
void _addDependenciesFromImpact(MemberEntity element) {
WorldImpact worldImpact = impactCache[element];
- worldImpact.apply(WorldImpactVisitorImpl(
- visitStaticUse: (MemberEntity member, StaticUse staticUse) {
- _addFromStaticUse(element, staticUse);
- }, visitTypeUse: (MemberEntity member, TypeUse typeUse) {
- _addFromTypeUse(element, typeUse);
- }, visitDynamicUse: (MemberEntity member, DynamicUse dynamicUse) {
- // TODO(johnniwinther): Use rti need data to skip unneeded type
- // arguments.
- addTypeListDependencies(dynamicUse.typeArguments);
- }));
+ worldImpact.forEachStaticUse(_addFromStaticUse);
+ worldImpact.forEachTypeUse(_addFromTypeUse);
+
+ // TODO(johnniwinther): Use rti need data to skip unneeded type
+ // arguments.
+ worldImpact.forEachDynamicUse(
+ (_, use) => addTypeListDependencies(use.typeArguments));
}
}
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 0101783..35a0e17 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -27,7 +27,7 @@
import 'js/js.dart' as jsAst;
import 'js_model/js_strategy.dart';
import 'js_backend/field_analysis.dart';
-import 'universe/world_impact.dart' show WorldImpact, WorldImpactVisitorImpl;
+import 'universe/world_impact.dart' show WorldImpact;
import 'util/sink_adapter.dart';
import 'world.dart' show JClosedWorld;
@@ -891,16 +891,17 @@
if (impact == null) return const <Selection>[];
var selections = <Selection>[];
- impact.apply(WorldImpactVisitorImpl(visitDynamicUse: (member, dynamicUse) {
+ impact.forEachDynamicUse((_, dynamicUse) {
AbstractValue mask = dynamicUse.receiverConstraint;
selections.addAll(closedWorld
// TODO(het): Handle `call` on `Closure` through
// `world.includesClosureCall`.
.locateMembers(dynamicUse.selector, mask)
.map((MemberEntity e) => Selection(e, mask)));
- }, visitStaticUse: (member, staticUse) {
+ });
+ impact.forEachStaticUse((_, staticUse) {
selections.add(Selection(staticUse.element, null));
- }));
+ });
unregisterImpact(entity);
return selections;
}
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 075a591..e003a60 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -11,7 +11,7 @@
import 'elements/entities.dart';
import 'elements/types.dart';
import 'universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse;
-import 'universe/world_impact.dart' show WorldImpact, WorldImpactVisitor;
+import 'universe/world_impact.dart' show WorldImpact;
abstract class EnqueuerListener {
/// Called to instruct to the backend that [type] has been instantiated.
@@ -80,8 +80,6 @@
// side-effects.
static bool skipEnqueuerCheckForTesting = false;
- WorldImpactVisitor get impactVisitor;
-
bool queueIsClosed;
bool get queueIsEmpty;
@@ -91,7 +89,10 @@
/// Apply the [worldImpact] to this enqueuer.
void applyImpact(WorldImpact worldImpact) {
if (worldImpact.isEmpty) return;
- worldImpact.apply(impactVisitor);
+ worldImpact.forEachStaticUse(processStaticUse);
+ worldImpact.forEachDynamicUse((_, use) => processDynamicUse(use));
+ worldImpact.forEachTypeUse(processTypeUse);
+ worldImpact.forEachConstantUse((_, use) => processConstantUse(use));
}
bool checkNoEnqueuedInvokedInstanceMethods(
@@ -137,32 +138,6 @@
}
}
-class EnqueuerImpactVisitor implements WorldImpactVisitor {
- final Enqueuer enqueuer;
-
- EnqueuerImpactVisitor(this.enqueuer);
-
- @override
- void visitDynamicUse(MemberEntity member, DynamicUse dynamicUse) {
- enqueuer.processDynamicUse(dynamicUse);
- }
-
- @override
- void visitStaticUse(MemberEntity member, StaticUse staticUse) {
- enqueuer.processStaticUse(member, staticUse);
- }
-
- @override
- void visitTypeUse(MemberEntity member, TypeUse typeUse) {
- enqueuer.processTypeUse(member, typeUse);
- }
-
- @override
- void visitConstantUse(MemberEntity member, ConstantUse constantUse) {
- enqueuer.processConstantUse(constantUse);
- }
-}
-
/// Interface for creating work items for enqueued member entities.
abstract class WorkItemBuilder {
WorkItem createWorkItem(covariant MemberEntity entity);
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index aa490af..716ea52 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -99,6 +99,12 @@
_stateAfterWhenFalseInternal = whenFalse;
}
+ /// Removes from the current [_state] any data from the boolean value of the
+ /// most recently visited node.
+ void _clearConditionalStateAfter() {
+ _stateAfterWhenTrueInternal = _stateAfterWhenFalseInternal = null;
+ }
+
final SideEffectsBuilder _sideEffectsBuilder;
final Map<JumpTarget, List<LocalState>> _breaksFor =
<JumpTarget, List<LocalState>>{};
@@ -257,15 +263,16 @@
var oldAccumulateIsChecks = _accumulateIsChecks;
_accumulateIsChecks = conditionContext;
var result = node?.accept(this);
+
+ // Clear the conditional state to ensure we don't accidentally carry over
+ // conclusions from a nested condition into an outer condition. For example:
+ //
+ // if (methodCall(x is T && true)) { /* don't assume x is T here. */ }
+ if (!conditionContext) _clearConditionalStateAfter();
_accumulateIsChecks = oldAccumulateIsChecks;
return result;
}
- void visitList(List<ir.Node> nodes) {
- if (nodes == null) return;
- nodes.forEach(visit);
- }
-
void handleParameter(ir.VariableDeclaration node, {bool isOptional}) {
Local local = _localsMap.getLocalVariable(node);
DartType type = _localsMap.getLocalType(_elementMap, local);
@@ -1696,11 +1703,7 @@
}
TypeInformation handleCondition(ir.Node node) {
- bool oldAccumulateIsChecks = _accumulateIsChecks;
- _accumulateIsChecks = true;
- TypeInformation result = visit(node, conditionContext: true);
- _accumulateIsChecks = oldAccumulateIsChecks;
- return result;
+ return visit(node, conditionContext: true);
}
void _potentiallyAddIsCheck(ir.IsExpression node) {
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 5fd435b..9185917 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -24,7 +24,6 @@
StaticUseKind,
TypeUse,
TypeUseKind;
-import '../universe/world_impact.dart' show WorldImpactVisitor;
import '../util/enumset.dart';
import '../util/util.dart' show Setlet;
@@ -44,9 +43,6 @@
final EnqueuerListener listener;
final AnnotationsData _annotationsData;
- @override
- WorldImpactVisitor impactVisitor;
-
final Queue<WorkItem> _queue = Queue<WorkItem>();
/// All declaration elements that have been processed by codegen.
@@ -58,9 +54,7 @@
CodegenEnqueuer(this.task, this.worldBuilder, this._workItemBuilder,
this.listener, this._annotationsData)
- : this.name = 'codegen enqueuer' {
- impactVisitor = EnqueuerImpactVisitor(this);
- }
+ : this.name = 'codegen enqueuer';
@override
Iterable<ClassEntity> get directlyInstantiatedClasses =>
diff --git a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
index 30dd0b8..8f60070 100644
--- a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
@@ -10,9 +10,15 @@
class _FunctionData {
final List<AwaitExpression> awaits = [];
- final List<ReturnStatement> returnStatements = [];
+ final Set<ReturnStatement> returnStatements = {};
_FunctionData();
+
+ /// Returns true if all [AwaitExpression]s are children of [ReturnStatement]s.
+ bool allAwaitsDirectReturn() {
+ return awaits.every(
+ (awaitExpression) => returnStatements.contains(awaitExpression.parent));
+ }
}
/// Handles simplification of basic 'async' functions into [Future]s.
@@ -59,9 +65,23 @@
]))));
}
+ void _transformDirectReturnAwaits(
+ FunctionNode node, _FunctionData functionData) {
+ // If every await is the direct child of a return statement then we can
+ // do the following transformation:
+ // return await e; --> return e;
+ final updatedReturns = <ReturnStatement>{};
+ for (final awaitExpression in functionData.awaits) {
+ final returnStatement = awaitExpression.parent as ReturnStatement;
+ updatedReturns.add(returnStatement);
+ awaitExpression.replaceWith(awaitExpression.operand);
+ }
+ }
+
void _transformAsyncFunctionNode(FunctionNode node) {
assert(_functions.isNotEmpty, 'Must be within a function scope.');
final functionData = _functions.last;
+ var isLowered = false;
if (functionData.awaits.isEmpty) {
// There are no awaits within this function so convert to a simple
// Future.sync call with the function's returned expressions. We use
@@ -90,6 +110,12 @@
// handle the unpacking of the returned future in that case.
// 3) The return type of the function is not specified. In this case we
// instantiate Future.value with 'dynamic'.
+ isLowered = true;
+ } else if (functionData.allAwaitsDirectReturn()) {
+ _transformDirectReturnAwaits(node, functionData);
+ isLowered = true;
+ }
+ if (isLowered) {
_wrapBodySync(node);
}
}
diff --git a/pkg/compiler/lib/src/resolution/enqueuer.dart b/pkg/compiler/lib/src/resolution/enqueuer.dart
index 89fcb44..6a20e9d 100644
--- a/pkg/compiler/lib/src/resolution/enqueuer.dart
+++ b/pkg/compiler/lib/src/resolution/enqueuer.dart
@@ -22,7 +22,6 @@
StaticUseKind,
TypeUse,
TypeUseKind;
-import '../universe/world_impact.dart' show WorldImpactVisitor;
import '../util/enumset.dart';
import '../util/util.dart' show Setlet;
@@ -44,9 +43,6 @@
@override
bool queueIsClosed = false;
- @override
- WorldImpactVisitor impactVisitor;
-
final Queue<WorkItem> _queue = Queue<WorkItem>();
// If not `null` this is called when the queue has been emptied. It allows for
@@ -55,9 +51,7 @@
ResolutionEnqueuer(this.task, this._reporter, this.listener,
this.worldBuilder, this._workItemBuilder, this._annotationsData,
- [this.name = 'resolution enqueuer']) {
- impactVisitor = EnqueuerImpactVisitor(this);
- }
+ [this.name = 'resolution enqueuer']);
@override
Iterable<ClassEntity> get directlyInstantiatedClasses =>
diff --git a/pkg/compiler/lib/src/universe/world_impact.dart b/pkg/compiler/lib/src/universe/world_impact.dart
index 0d319ea..acd7038 100644
--- a/pkg/compiler/lib/src/universe/world_impact.dart
+++ b/pkg/compiler/lib/src/universe/world_impact.dart
@@ -37,16 +37,19 @@
Iterable<ConstantUse> get constantUses => const [];
- bool get isEmpty => true;
+ void _forEach<U>(Iterable<U> uses, void Function(MemberEntity, U) visitUse) =>
+ uses.forEach((use) => visitUse(member, use));
- void apply(WorldImpactVisitor visitor) {
- staticUses.forEach((StaticUse use) => visitor.visitStaticUse(member, use));
- dynamicUses
- .forEach((DynamicUse use) => visitor.visitDynamicUse(member, use));
- typeUses.forEach((TypeUse use) => visitor.visitTypeUse(member, use));
- constantUses
- .forEach((ConstantUse use) => visitor.visitConstantUse(member, use));
- }
+ void forEachDynamicUse(void Function(MemberEntity, DynamicUse) visitUse) =>
+ _forEach(dynamicUses, visitUse);
+ void forEachStaticUse(void Function(MemberEntity, StaticUse) visitUse) =>
+ _forEach(staticUses, visitUse);
+ void forEachTypeUse(void Function(MemberEntity, TypeUse) visitUse) =>
+ _forEach(typeUses, visitUse);
+ void forEachConstantUse(void Function(MemberEntity, ConstantUse) visitUse) =>
+ _forEach(constantUses, visitUse);
+
+ bool get isEmpty => true;
@override
String toString() => dump(this);
@@ -240,59 +243,3 @@
return sb.toString();
}
}
-
-/// Visitor used to process the uses of a [WorldImpact].
-abstract class WorldImpactVisitor {
- void visitStaticUse(MemberEntity member, StaticUse staticUse);
- void visitDynamicUse(MemberEntity member, DynamicUse dynamicUse);
- void visitTypeUse(MemberEntity member, TypeUse typeUse);
- void visitConstantUse(MemberEntity member, ConstantUse typeUse);
-}
-
-// TODO(johnniwinther): Remove these when we get anonymous local classes.
-typedef VisitUse<U> = void Function(MemberEntity member, U use);
-
-class WorldImpactVisitorImpl implements WorldImpactVisitor {
- final VisitUse<StaticUse> _visitStaticUse;
- final VisitUse<DynamicUse> _visitDynamicUse;
- final VisitUse<TypeUse> _visitTypeUse;
- final VisitUse<ConstantUse> _visitConstantUse;
-
- WorldImpactVisitorImpl(
- {VisitUse<StaticUse> visitStaticUse,
- VisitUse<DynamicUse> visitDynamicUse,
- VisitUse<TypeUse> visitTypeUse,
- VisitUse<ConstantUse> visitConstantUse})
- : _visitStaticUse = visitStaticUse,
- _visitDynamicUse = visitDynamicUse,
- _visitTypeUse = visitTypeUse,
- _visitConstantUse = visitConstantUse;
-
- @override
- void visitStaticUse(MemberEntity member, StaticUse use) {
- if (_visitStaticUse != null) {
- _visitStaticUse(member, use);
- }
- }
-
- @override
- void visitDynamicUse(MemberEntity member, DynamicUse use) {
- if (_visitDynamicUse != null) {
- _visitDynamicUse(member, use);
- }
- }
-
- @override
- void visitTypeUse(MemberEntity member, TypeUse use) {
- if (_visitTypeUse != null) {
- _visitTypeUse(member, use);
- }
- }
-
- @override
- void visitConstantUse(MemberEntity member, ConstantUse use) {
- if (_visitConstantUse != null) {
- _visitConstantUse(member, use);
- }
- }
-}
diff --git a/pkg/compiler/test/inference/data/issue_48571.dart b/pkg/compiler/test/inference/data/issue_48571.dart
new file mode 100644
index 0000000..c9c6a9c
--- /dev/null
+++ b/pkg/compiler/test/inference/data/issue_48571.dart
@@ -0,0 +1,83 @@
+// 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.
+
+/*member: Base.:[subclass=Base]*/
+abstract class Base {}
+
+/*member: Child1.:[exact=Child1]*/
+class Child1 extends Base {}
+
+/*member: Child2.:[exact=Child2]*/
+class Child2 extends Base {}
+
+/*member: trivial:Value([exact=JSBool], value: true)*/
+bool trivial(/*[exact=JSBool]*/ x) => true;
+
+/*member: either:Union([exact=Child1], [exact=Child2])*/
+Base either = DateTime.now()
+ . /*[exact=DateTime]*/ millisecondsSinceEpoch /*invoke: [subclass=JSInt]*/ >
+ 0
+ ? Child2()
+ : Child1();
+
+/*member: test1:Union(null, [exact=Child1], [exact=Child2])*/
+test1() {
+ Base child = either;
+ if (trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+/*member: test2:Union(null, [exact=Child1], [exact=Child2])*/
+test2() {
+ Base child = either;
+ if (child is Child1 || trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+/*member: test3:[null|exact=Child2]*/
+test3() {
+ Base child = either;
+ if (trivial(child is Child1 && true) && child is Child2) return child;
+ return null;
+}
+
+/*member: test4:[null|exact=Child2]*/
+test4() {
+ Base child = either;
+ if (child is Child2 && trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+/*member: test5:Union(null, [exact=Child1], [exact=Child2])*/
+test5() {
+ Base child = either;
+ if ((child is Child1 && true) /*invoke: [exact=JSBool]*/ == false)
+ return child;
+ return null;
+}
+
+/*member: test6:Union(null, [exact=Child1], [exact=Child2])*/
+test6() {
+ Base child = either;
+ if (trivial(child is Child1 ? false : true)) return child;
+ return null;
+}
+
+/*member: test7:Union(null, [exact=Child1], [exact=Child2])*/
+test7() {
+ Base child = either;
+ if (trivial(trivial(child is Child1 && true))) return child;
+ return null;
+}
+
+/*member: main:[null]*/
+main() {
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+ test6();
+ test7();
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart
new file mode 100644
index 0000000..8f917fa
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart
@@ -0,0 +1,26 @@
+Future<int> bar() {
+ return Future.value(123);
+}
+
+// Simple return-await statement.
+Future<int> foo1() async {
+ return await bar();
+}
+
+// Multiple return-await statements.
+Future<int> foo2(bool x) async {
+ if (x) return await Future.value(345);
+ return await bar();
+}
+
+// Combination of await and non-await returns. Wrap unawaited returns.
+Future<int> foo3(bool x) async {
+ if (x) return 234;
+ return await Future.value(123);
+}
+
+void main() {
+ foo1();
+ foo2(true);
+ foo3(true);
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.expect
new file mode 100644
index 0000000..7ea06af
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.expect
@@ -0,0 +1,26 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+
+static method bar() → asy::Future<core::int> {
+ return asy::Future::value<core::int>(123);
+}
+static method foo1() → asy::Future<core::int> async /* futureValueType= core::int */ {
+ return await self::bar();
+}
+static method foo2(core::bool x) → asy::Future<core::int> async /* futureValueType= core::int */ {
+ if(x)
+ return await asy::Future::value<core::int>(345);
+ return await self::bar();
+}
+static method foo3(core::bool x) → asy::Future<core::int> async /* futureValueType= core::int */ {
+ if(x)
+ return 234;
+ return await asy::Future::value<core::int>(123);
+}
+static method main() → void {
+ self::foo1();
+ self::foo2(true);
+ self::foo3(true);
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect
new file mode 100644
index 0000000..0e794df
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+
+static method bar() → asy::Future<core::int> {
+ return asy::Future::value<core::int>(123);
+}
+static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */
+ return asy::Future::sync<core::int>(() → FutureOr<core::int> {
+ return self::bar();
+ });
+static method foo2(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */
+ return asy::Future::sync<core::int>(() → FutureOr<core::int> {
+ if(x)
+ return asy::Future::value<core::int>(345);
+ return self::bar();
+ });
+static method foo3(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */
+ return asy::Future::sync<core::int>(() → FutureOr<core::int> {
+ if(x)
+ return 234;
+ return asy::Future::value<core::int>(123);
+ });
+static method main() → void {
+ self::foo1();
+ self::foo2(true);
+ self::foo3(true);
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.textual_outline.expect
new file mode 100644
index 0000000..a361918
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.textual_outline.expect
@@ -0,0 +1,5 @@
+Future<int> bar() {}
+Future<int> foo1() async {}
+Future<int> foo2(bool x) async {}
+Future<int> foo3(bool x) async {}
+void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a361918
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.textual_outline_modelled.expect
@@ -0,0 +1,5 @@
+Future<int> bar() {}
+Future<int> foo1() async {}
+Future<int> foo2(bool x) async {}
+Future<int> foo3(bool x) async {}
+void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.expect
new file mode 100644
index 0000000..7ea06af
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.expect
@@ -0,0 +1,26 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+
+static method bar() → asy::Future<core::int> {
+ return asy::Future::value<core::int>(123);
+}
+static method foo1() → asy::Future<core::int> async /* futureValueType= core::int */ {
+ return await self::bar();
+}
+static method foo2(core::bool x) → asy::Future<core::int> async /* futureValueType= core::int */ {
+ if(x)
+ return await asy::Future::value<core::int>(345);
+ return await self::bar();
+}
+static method foo3(core::bool x) → asy::Future<core::int> async /* futureValueType= core::int */ {
+ if(x)
+ return 234;
+ return await asy::Future::value<core::int>(123);
+}
+static method main() → void {
+ self::foo1();
+ self::foo2(true);
+ self::foo3(true);
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.modular.expect
new file mode 100644
index 0000000..7ea06af
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.modular.expect
@@ -0,0 +1,26 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+
+static method bar() → asy::Future<core::int> {
+ return asy::Future::value<core::int>(123);
+}
+static method foo1() → asy::Future<core::int> async /* futureValueType= core::int */ {
+ return await self::bar();
+}
+static method foo2(core::bool x) → asy::Future<core::int> async /* futureValueType= core::int */ {
+ if(x)
+ return await asy::Future::value<core::int>(345);
+ return await self::bar();
+}
+static method foo3(core::bool x) → asy::Future<core::int> async /* futureValueType= core::int */ {
+ if(x)
+ return 234;
+ return await asy::Future::value<core::int>(123);
+}
+static method main() → void {
+ self::foo1();
+ self::foo2(true);
+ self::foo3(true);
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.outline.expect
new file mode 100644
index 0000000..b0cdf1c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.outline.expect
@@ -0,0 +1,15 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+
+static method bar() → asy::Future<core::int>
+ ;
+static method foo1() → asy::Future<core::int> async
+ ;
+static method foo2(core::bool x) → asy::Future<core::int> async
+ ;
+static method foo3(core::bool x) → asy::Future<core::int> async
+ ;
+static method main() → void
+ ;
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect
new file mode 100644
index 0000000..0e794df
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:async" as asy;
+import "dart:core" as core;
+
+static method bar() → asy::Future<core::int> {
+ return asy::Future::value<core::int>(123);
+}
+static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */
+ return asy::Future::sync<core::int>(() → FutureOr<core::int> {
+ return self::bar();
+ });
+static method foo2(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */
+ return asy::Future::sync<core::int>(() → FutureOr<core::int> {
+ if(x)
+ return asy::Future::value<core::int>(345);
+ return self::bar();
+ });
+static method foo3(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */
+ return asy::Future::sync<core::int>(() → FutureOr<core::int> {
+ if(x)
+ return 234;
+ return asy::Future::value<core::int>(123);
+ });
+static method main() → void {
+ self::foo1();
+ self::foo2(true);
+ self::foo3(true);
+}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
index 8581d4c..bbef654 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
@@ -1,9 +1,11 @@
+// Contains await with no return.
Future<void> foo1() async {
await 6;
}
+// Await is not direct child of return.
Future<int> foo2() async {
- return await 6;
+ return (await 6) + 3;
}
void main() {
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
index 10798bd8..eb616ff 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
@@ -7,7 +7,7 @@
await 6;
}
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
- return await 6;
+ return (await 6).{core::num::+}(3){(core::num) → core::int};
}
static method main() → void {
self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
index 10798bd8..eb616ff 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
@@ -7,7 +7,7 @@
await 6;
}
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
- return await 6;
+ return (await 6).{core::num::+}(3){(core::num) → core::int};
}
static method main() → void {
self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
index 10798bd8..eb616ff 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
@@ -7,7 +7,7 @@
await 6;
}
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
- return await 6;
+ return (await 6).{core::num::+}(3){(core::num) → core::int};
}
static method main() → void {
self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
index 10798bd8..eb616ff 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
@@ -7,7 +7,7 @@
await 6;
}
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
- return await 6;
+ return (await 6).{core::num::+}(3){(core::num) → core::int};
}
static method main() → void {
self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
index 10798bd8..eb616ff 100644
--- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
@@ -7,7 +7,7 @@
await 6;
}
static method foo2() → asy::Future<core::int> async /* futureValueType= core::int */ {
- return await 6;
+ return (await 6).{core::num::+}(3){(core::num) → core::int};
}
static method main() → void {
self::foo1();
diff --git a/tests/web/regress/issue/48571_test.dart b/tests/web/regress/issue/48571_test.dart
new file mode 100644
index 0000000..9a15a70
--- /dev/null
+++ b/tests/web/regress/issue/48571_test.dart
@@ -0,0 +1,66 @@
+// 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:expect/expect.dart';
+
+abstract class Base {}
+
+class Child1 extends Base {}
+
+class Child2 extends Base {}
+
+bool trivial(x) => true;
+Base either = DateTime.now().millisecondsSinceEpoch > 0 ? Child2() : Child1();
+
+test1() {
+ Base child = either;
+ if (trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+test2() {
+ Base child = either;
+ if (child is Child1 || trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+test3() {
+ Base child = either;
+ if (trivial(child is Child1 && true) && child is Child2) return child;
+ return null;
+}
+
+test4() {
+ Base child = either;
+ if (child is Child2 && trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+test5() {
+ Base child = either;
+ if ((child is Child1 && true) == false) return child;
+ return null;
+}
+
+test6() {
+ Base child = either;
+ if (trivial(child is Child1 ? false : true)) return child;
+ return null;
+}
+
+test7() {
+ Base child = either;
+ if (trivial(trivial(child is Child1 && true))) return child;
+ return null;
+}
+
+main() {
+ Expect.isTrue(test1() is Child2, "test1");
+ Expect.isTrue(test2() is Child2, "test2");
+ Expect.isTrue(test3() is Child2, "test3");
+ Expect.isTrue(test4() is Child2, "test4");
+ Expect.isTrue(test5() is Child2, "test5");
+ Expect.isTrue(test6() is Child2, "test6");
+ Expect.isTrue(test7() is Child2, "test7");
+}
diff --git a/tests/web_2/regress/issue/48571_test.dart b/tests/web_2/regress/issue/48571_test.dart
new file mode 100644
index 0000000..d724ffa
--- /dev/null
+++ b/tests/web_2/regress/issue/48571_test.dart
@@ -0,0 +1,68 @@
+// 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.
+
+// @dart = 2.7
+
+import 'package:expect/expect.dart';
+
+abstract class Base {}
+
+class Child1 extends Base {}
+
+class Child2 extends Base {}
+
+bool trivial(x) => true;
+Base either = DateTime.now().millisecondsSinceEpoch > 0 ? Child2() : Child1();
+
+test1() {
+ Base child = either;
+ if (trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+test2() {
+ Base child = either;
+ if (child is Child1 || trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+test3() {
+ Base child = either;
+ if (trivial(child is Child1 && true) && child is Child2) return child;
+ return null;
+}
+
+test4() {
+ Base child = either;
+ if (child is Child2 && trivial(child is Child1 && true)) return child;
+ return null;
+}
+
+test5() {
+ Base child = either;
+ if ((child is Child1 && true) == false) return child;
+ return null;
+}
+
+test6() {
+ Base child = either;
+ if (trivial(child is Child1 ? false : true)) return child;
+ return null;
+}
+
+test7() {
+ Base child = either;
+ if (trivial(trivial(child is Child1 && true))) return child;
+ return null;
+}
+
+main() {
+ Expect.isTrue(test1() is Child2, "test1");
+ Expect.isTrue(test2() is Child2, "test2");
+ Expect.isTrue(test3() is Child2, "test3");
+ Expect.isTrue(test4() is Child2, "test4");
+ Expect.isTrue(test5() is Child2, "test5");
+ Expect.isTrue(test6() is Child2, "test6");
+ Expect.isTrue(test7() is Child2, "test7");
+}
diff --git a/tools/VERSION b/tools/VERSION
index 8d5cf70..6233344 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 276
+PRERELEASE 277
PRERELEASE_PATCH 0
\ No newline at end of file