Skip to content

Commit 67a93da

Browse files
committed
Handle type literals correctly with deferred loading and await.
When referring to constants via a deferred prefix in an await expression the transformation must make sure that the generated code before and after the deferred load agree on the number of captured variables. (i.e. the number of await-temp variables introduced by the await-transformer is the same) This CL uses a temporary in the case of compile-time constants, because before the deferred load, a reference lib.C is translated into a static getter which also requires a temporary. Fixes #28678 [email protected] Review-Url: https://codereview.chromium.org/2683973002 .
1 parent aa64ca9 commit 67a93da

File tree

5 files changed

+61
-7
lines changed

5 files changed

+61
-7
lines changed

runtime/vm/ast.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,12 @@ class LiteralNode : public AstNode {
443443

444444
class TypeNode : public AstNode {
445445
public:
446-
TypeNode(TokenPosition token_pos, const AbstractType& type)
447-
: AstNode(token_pos), type_(type) {
446+
TypeNode(TokenPosition token_pos,
447+
const AbstractType& type,
448+
bool is_deferred_reference = false)
449+
: AstNode(token_pos),
450+
type_(type),
451+
is_deferred_reference_(is_deferred_reference) {
448452
ASSERT(type_.IsZoneHandle());
449453
ASSERT(!type_.IsNull());
450454
ASSERT(type_.IsFinalized());
@@ -466,10 +470,14 @@ class TypeNode : public AstNode {
466470

467471
virtual void VisitChildren(AstNodeVisitor* visitor) const {}
468472

473+
bool is_deferred_reference() const { return is_deferred_reference_; }
474+
void set_is_deferred_reference(bool value) { is_deferred_reference_ = value; }
475+
469476
DECLARE_COMMON_NODE_FUNCTIONS(TypeNode);
470477

471478
private:
472479
const AbstractType& type_;
480+
bool is_deferred_reference_;
473481

474482
DISALLOW_IMPLICIT_CONSTRUCTORS(TypeNode);
475483
};

runtime/vm/ast_transformer.cc

+8-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,14 @@ void AwaitTransformer::VisitLiteralNode(LiteralNode* node) {
119119

120120

121121
void AwaitTransformer::VisitTypeNode(TypeNode* node) {
122-
result_ = new (Z) TypeNode(node->token_pos(), node->type());
122+
if (node->is_deferred_reference()) {
123+
// Deferred references must use a temporary even after loading
124+
// happened, so that the number of await temps is the same as
125+
// before the loading.
126+
result_ = MakeName(node);
127+
} else {
128+
result_ = node;
129+
}
123130
}
124131

125132

runtime/vm/parser.cc

+8-4
Original file line numberDiff line numberDiff line change
@@ -11837,7 +11837,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
1183711837
type ^= CanonicalizeType(type);
1183811838
// Type may be malbounded, but not malformed.
1183911839
ASSERT(!type.IsMalformed());
11840-
array = new (Z) TypeNode(primary_pos, type);
11840+
array = new (Z) TypeNode(primary_pos, type,
11841+
primary_node->is_deferred_reference());
1184111842
} else if (primary_node->primary().IsTypeParameter()) {
1184211843
array = LoadTypeParameter(primary_node);
1184311844
} else {
@@ -11931,7 +11932,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
1193111932
type ^= CanonicalizeType(type);
1193211933
// Type may be malbounded, but not malformed.
1193311934
ASSERT(!type.IsMalformed());
11934-
selector = new (Z) TypeNode(primary_pos, type);
11935+
selector = new (Z) TypeNode(primary_pos, type,
11936+
primary_node->is_deferred_reference());
1193511937
} else {
1193611938
UNREACHABLE(); // Internal parser error.
1193711939
}
@@ -11957,7 +11959,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
1195711959
type = CanonicalizeType(type);
1195811960
// Type may be malbounded, but not malformed.
1195911961
ASSERT(!type.IsMalformed());
11960-
left = new (Z) TypeNode(primary_pos, type);
11962+
left = new (Z) TypeNode(primary_pos, type,
11963+
primary_node->is_deferred_reference());
1196111964
} else if (primary_node->primary().IsTypeParameter()) {
1196211965
left = LoadTypeParameter(primary_node);
1196311966
} else if (primary_node->IsSuper()) {
@@ -12878,7 +12881,8 @@ AstNode* Parser::ResolveIdent(TokenPosition ident_pos,
1287812881
type ^= CanonicalizeType(type);
1287912882
// Type may be malbounded, but not malformed.
1288012883
ASSERT(!type.IsMalformed());
12881-
resolved = new (Z) TypeNode(primary_pos, type);
12884+
resolved =
12885+
new (Z) TypeNode(primary_pos, type, primary->is_deferred_reference());
1288212886
}
1288312887
}
1288412888
return resolved;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2017, 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+
var v;
6+
7+
class Clazz { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2017, 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+
// Test that await after deferred loading works as expected.
6+
7+
import 'dart:async';
8+
import "package:expect/expect.dart";
9+
import 'deferred_regression_28678_lib.dart' deferred as lib;
10+
11+
class A {
12+
m() => "here";
13+
}
14+
15+
f(a, b) => new Future.microtask(() {});
16+
17+
class R {
18+
Future test_deferred() async {
19+
var a = new A();
20+
await lib.loadLibrary();
21+
await f(lib.Clazz, lib.v);
22+
Expect.equals("here", a.m());
23+
}
24+
}
25+
26+
main() async {
27+
await new R().test_deferred();
28+
}

0 commit comments

Comments
 (0)