Skip to content

Commit 6b12473

Browse files
alexmarkovCommit Queue
authored and
Commit Queue
committed
[vm] Adjust return value of async/async*/sync* after the language spec change
Calculation of element type for the value returned from async/async*/sync* functions was recently adjusted in the spec to address soundness issue (dart-lang/language#3218). This change adjusts Dart VM to conform to the new spec. TEST=language/async/regression_54311_test TEST=co19/Language/Functions/element_type_* Fixes #54316 Issue #54311 Issue #54159 Change-Id: I4c51e7cba704d034350519375210bdb2086c5432 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/342082 Reviewed-by: Alexander Aprelev <aam@google.com> Reviewed-by: Erik Ernst <eernst@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
1 parent e58efcb commit 6b12473

File tree

4 files changed

+73
-35
lines changed

4 files changed

+73
-35
lines changed

runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc

+37-34
Original file line numberDiff line numberDiff line change
@@ -559,33 +559,25 @@ Fragment StreamingFlowGraphBuilder::SetupCapturedParameters(
559559
}
560560

561561
Fragment StreamingFlowGraphBuilder::InitSuspendableFunction(
562-
const Function& dart_function) {
562+
const Function& dart_function,
563+
const AbstractType* emitted_value_type) {
563564
Fragment body;
564565
if (dart_function.IsAsyncFunction()) {
565-
const auto& result_type =
566-
AbstractType::Handle(Z, dart_function.result_type());
567-
auto& type_args = TypeArguments::ZoneHandle(Z);
568-
if (result_type.IsType() &&
569-
(Class::Handle(Z, result_type.type_class()).IsFutureClass() ||
570-
result_type.IsFutureOrType())) {
571-
ASSERT(result_type.IsFinalized());
572-
type_args = Type::Cast(result_type).GetInstanceTypeArguments(H.thread());
573-
}
574-
566+
ASSERT(emitted_value_type != nullptr);
567+
auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(1));
568+
type_args.SetTypeAt(0, *emitted_value_type);
569+
type_args = Class::Handle(Z, IG->object_store()->future_class())
570+
.GetInstanceTypeArguments(H.thread(), type_args);
575571
body += TranslateInstantiatedTypeArguments(type_args);
576572
body += B->Call1ArgStub(TokenPosition::kNoSource,
577573
Call1ArgStubInstr::StubId::kInitAsync);
578574
body += Drop();
579575
} else if (dart_function.IsAsyncGenerator()) {
580-
const auto& result_type =
581-
AbstractType::Handle(Z, dart_function.result_type());
582-
auto& type_args = TypeArguments::ZoneHandle(Z);
583-
if (result_type.IsType() &&
584-
(result_type.type_class() == IG->object_store()->stream_class())) {
585-
ASSERT(result_type.IsFinalized());
586-
type_args = Type::Cast(result_type).GetInstanceTypeArguments(H.thread());
587-
}
588-
576+
ASSERT(emitted_value_type != nullptr);
577+
auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(1));
578+
type_args.SetTypeAt(0, *emitted_value_type);
579+
type_args = Class::Handle(Z, IG->object_store()->stream_class())
580+
.GetInstanceTypeArguments(H.thread(), type_args);
589581
body += TranslateInstantiatedTypeArguments(type_args);
590582
body += B->Call1ArgStub(TokenPosition::kNoSource,
591583
Call1ArgStubInstr::StubId::kInitAsyncStar);
@@ -595,15 +587,11 @@ Fragment StreamingFlowGraphBuilder::InitSuspendableFunction(
595587
SuspendInstr::StubId::kYieldAsyncStar);
596588
body += Drop();
597589
} else if (dart_function.IsSyncGenerator()) {
598-
const auto& result_type =
599-
AbstractType::Handle(Z, dart_function.result_type());
600-
auto& type_args = TypeArguments::ZoneHandle(Z);
601-
if (result_type.IsType() &&
602-
(result_type.type_class() == IG->object_store()->iterable_class())) {
603-
ASSERT(result_type.IsFinalized());
604-
type_args = Type::Cast(result_type).GetInstanceTypeArguments(H.thread());
605-
}
606-
590+
ASSERT(emitted_value_type != nullptr);
591+
auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(1));
592+
type_args.SetTypeAt(0, *emitted_value_type);
593+
type_args = Class::Handle(Z, IG->object_store()->iterable_class())
594+
.GetInstanceTypeArguments(H.thread(), type_args);
607595
body += TranslateInstantiatedTypeArguments(type_args);
608596
body += B->Call1ArgStub(TokenPosition::kNoSource,
609597
Call1ArgStubInstr::StubId::kInitSyncStar);
@@ -618,6 +606,8 @@ Fragment StreamingFlowGraphBuilder::InitSuspendableFunction(
618606
if (scope->num_context_variables() > 0) {
619607
body += CloneContext(scope->context_slots());
620608
}
609+
} else {
610+
ASSERT(emitted_value_type == nullptr);
621611
}
622612
return body;
623613
}
@@ -784,17 +774,30 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(
784774

785775
LocalVariable* first_parameter = nullptr;
786776
TokenPosition token_position = TokenPosition::kNoSource;
777+
const AbstractType* emitted_value_type = nullptr;
787778
{
788779
AlternativeReadingScope alt(&reader_);
789780
FunctionNodeHelper function_node_helper(this);
790781
function_node_helper.ReadUntilExcluding(
791782
FunctionNodeHelper::kPositionalParameters);
792-
intptr_t list_length = ReadListLength(); // read number of positionals.
793-
if (list_length > 0) {
794-
intptr_t first_parameter_offset = ReaderOffset() + data_program_offset_;
795-
first_parameter = LookupVariable(first_parameter_offset);
783+
{
784+
AlternativeReadingScope alt2(&reader_);
785+
intptr_t list_length = ReadListLength(); // read number of positionals.
786+
if (list_length > 0) {
787+
intptr_t first_parameter_offset = ReaderOffset() + data_program_offset_;
788+
first_parameter = LookupVariable(first_parameter_offset);
789+
}
796790
}
797791
token_position = function_node_helper.position_;
792+
if (dart_function.IsSuspendableFunction()) {
793+
function_node_helper.ReadUntilExcluding(
794+
FunctionNodeHelper::kEmittedValueType);
795+
if (ReadTag() == kSomething) {
796+
emitted_value_type = &T.BuildType(); // read emitted value type.
797+
} else {
798+
UNREACHABLE();
799+
}
800+
}
798801
}
799802

800803
auto graph_entry = flow_graph_builder_->graph_entry_ =
@@ -833,7 +836,7 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(
833836
// objects than necessary during GC.
834837
const Fragment body =
835838
ClearRawParameters(dart_function) + B->BuildNullAssertions() +
836-
InitSuspendableFunction(dart_function) +
839+
InitSuspendableFunction(dart_function, emitted_value_type) +
837840
BuildFunctionBody(dart_function, first_parameter, is_constructor);
838841

839842
auto extra_entry_point_style =

runtime/vm/compiler/frontend/kernel_binary_flowgraph.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
8585
TokenPosition position);
8686
Fragment CheckStackOverflowInPrologue(const Function& dart_function);
8787
Fragment SetupCapturedParameters(const Function& dart_function);
88-
Fragment InitSuspendableFunction(const Function& dart_function);
88+
Fragment InitSuspendableFunction(const Function& dart_function,
89+
const AbstractType* emitted_value_type);
8990
Fragment ShortcutForUserDefinedEquals(const Function& dart_function,
9091
LocalVariable* first_parameter);
9192
Fragment TypeArgumentsHandling(const Function& dart_function);

runtime/vm/compiler/frontend/scope_builder.cc

+5
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() {
243243
// async/async*/sync* function. It may reference receiver or type
244244
// arguments of the enclosing function which need to be captured.
245245
VisitDartType();
246+
247+
// Visit optional future value type.
248+
if (helper_.ReadTag() == kSomething) {
249+
VisitDartType();
250+
}
246251
}
247252

248253
// We generate a synthetic body for implicit closure functions - which
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Verifies that futureValueType(FutureOr<Object>) = Object.
6+
//
7+
// This is a special case because NORM(FutureOr<Object>) = Object,
8+
// and futureValueType(Object) = Object?, so futureValueType cannot be
9+
// applied to a normalized type.
10+
//
11+
// Regression test for https://github.com/dart-lang/sdk/issues/54311.
12+
13+
import 'dart:async';
14+
15+
import "package:expect/expect.dart";
16+
17+
FutureOr<Object> fn1() async {
18+
return Future<Object>.value(42);
19+
}
20+
21+
FutureOr<Object> fn2() async => 42;
22+
23+
void main() async {
24+
final value1 = await fn1();
25+
Expect.equals(42, value1);
26+
27+
final value2 = await fn2();
28+
Expect.equals(42, value2);
29+
}

0 commit comments

Comments
 (0)