Skip to content

Commit e84bea2

Browse files
jensjohacommit-bot@chromium.org
authored andcommitted
[CFE] Fix crash in incremental compiler caused by async redirecting factory
Redirectig factories are encoded in a special way to "recover" their data (together with _redirecting# field). Before this CL, if a redirecting factory was async (that's an error) it was encoded so we couldn't load that dill again and that we would throw an error if we tried. This CL fixes that. Change-Id: If73ef5f662fb23bc083eb1af086d9d7694ca538c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133061 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent 44316ea commit e84bea2

File tree

4 files changed

+69
-51
lines changed

4 files changed

+69
-51
lines changed

pkg/front_end/lib/src/fasta/source/diet_listener.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class DietListener extends StackListenerImpl {
9797

9898
DeclarationBuilder _currentDeclaration;
9999
ClassBuilder _currentClass;
100+
bool _inRedirectingFactory = false;
100101

101102
bool currentClassIsParserRecovery = false;
102103

@@ -590,7 +591,7 @@ class DietListener extends StackListenerImpl {
590591
if (name is ParserRecovery || currentClassIsParserRecovery) return;
591592

592593
FunctionBuilder builder = lookupConstructor(beginToken, name);
593-
if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
594+
if (_inRedirectingFactory) {
594595
buildRedirectingFactoryMethod(
595596
bodyToken, builder, MemberKind.Factory, metadata);
596597
} else {
@@ -625,6 +626,7 @@ class DietListener extends StackListenerImpl {
625626
void endRedirectingFactoryBody(Token beginToken, Token endToken) {
626627
debugEvent("RedirectingFactoryBody");
627628
discard(1); // ConstructorReference.
629+
_inRedirectingFactory = true;
628630
}
629631

630632
@override
@@ -793,6 +795,7 @@ class DietListener extends StackListenerImpl {
793795
void endMember() {
794796
debugEvent("Member");
795797
checkEmpty(-1);
798+
_inRedirectingFactory = false;
796799
}
797800

798801
@override
@@ -933,6 +936,11 @@ class DietListener extends StackListenerImpl {
933936
token = parser.parseInitializersOpt(token);
934937
token = parser.parseAsyncModifierOpt(token);
935938
AsyncMarker asyncModifier = getAsyncMarker(listener) ?? AsyncMarker.Sync;
939+
if (kind == MemberKind.Factory && asyncModifier != AsyncMarker.Sync) {
940+
// Factories has to be sync. The parser issued an error.
941+
// Recover to sync.
942+
asyncModifier = AsyncMarker.Sync;
943+
}
936944
bool isExpression = false;
937945
bool allowAbstract = asyncModifier == AsyncMarker.Sync;
938946
parser.parseFunctionBody(token, isExpression, allowAbstract);

pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,31 @@ worlds:
99
- entry: main.dart
1010
sources:
1111
main.dart: |
12+
import "lib.dart";
13+
void main() {
14+
var c = new C.e4();
15+
}
16+
lib.dart: |
1217
class C {
1318
C();
1419
factory C.e4() async = C;
1520
}
16-
21+
expectedLibraryCount: 2
22+
errors: true
23+
- entry: main.dart
24+
invalidate:
25+
- main.dart
26+
sources:
27+
main.dart: |
28+
import "lib.dart";
1729
void main() {
1830
var c = new C.e4();
31+
print(c);
32+
}
33+
lib.dart: |
34+
class C {
35+
C();
36+
factory C.e4() async = C;
1937
}
20-
expectedLibraryCount: 1
38+
expectedLibraryCount: 2
2139
errors: true
Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,27 @@
11
main = <No Member>;
2-
library from "org-dartlang-test:///main.dart" as main {
2+
library from "org-dartlang-test:///lib.dart" as lib {
33
//
44
// Problems in library:
55
//
6-
// org-dartlang-test:///main.dart:3:11: Error: Functions marked 'async' must have a return type assignable to 'Future'.
7-
// factory C.e4() async = C;
8-
// ^^
9-
//
10-
// org-dartlang-test:///main.dart:3:18: Error: Factory bodies can't use 'async', 'async*', or 'sync*'.
6+
// org-dartlang-test:///lib.dart:3:18: Error: Factory bodies can't use 'async', 'async*', or 'sync*'.
117
// factory C.e4() async = C;
128
// ^^^^^
13-
//
14-
// org-dartlang-test:///main.dart:3:24: Error: Expected a function body or '=>'.
15-
// Try adding {}.
16-
// factory C.e4() async = C;
17-
// ^
18-
//
19-
// org-dartlang-test:///main.dart:3:26: Error: A value of type 'Type' can't be assigned to a variable of type 'FutureOr<C>'.
20-
// - 'Type' is from 'dart:core'.
21-
// - 'FutureOr' is from 'dart:async'.
22-
// - 'C' is from 'org-dartlang-test:///main.dart'.
23-
// factory C.e4() async = C;
24-
// ^
259
//
2610

2711
class C extends dart.core::Object {
28-
static field dynamic _redirecting# = <dynamic>[main::C::e4];
29-
constructor •() → main::C*
12+
static field dynamic _redirecting# = <dynamic>[lib::C::e4];
13+
constructor •() → lib::C*
3014
: super dart.core::Object::•()
3115
;
32-
static factory e4() → main::C* /* originally async */ {
33-
final dart.async::_AsyncAwaitCompleter<dynamic>* :async_completer = new dart.async::_AsyncAwaitCompleter::•<dynamic>();
34-
dart.async::FutureOr<dynamic>* :return_value;
35-
dynamic :async_stack_trace;
36-
dynamic :async_op_then;
37-
dynamic :async_op_error;
38-
dart.core::int* :await_jump_var = 0;
39-
dynamic :await_ctx_var;
40-
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
41-
try {
42-
#L1:
43-
{
44-
:return_value = let final<BottomType> #t1 = invalid-expression "org-dartlang-test:///main.dart:3:26: Error: A value of type 'Type' can't be assigned to a variable of type 'FutureOr<C>'.\n - 'Type' is from 'dart:core'.\n - 'FutureOr' is from 'dart:async'.\n - 'C' is from 'org-dartlang-test:///main.dart'.\n factory C.e4() async = C;\n ^" in main::C* as{TypeError} dart.async::FutureOr<main::C*>*;
45-
break #L1;
46-
}
47-
dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
48-
return;
49-
}
50-
on dynamic catch(dynamic :exception, dynamic :stack_trace) {
51-
:async_completer.{dart.async::Completer::completeError}(:exception, :stack_trace);
52-
}
53-
:async_stack_trace = dart.async::_asyncStackTraceHelper(:async_op);
54-
:async_op_then = dart.async::_asyncThenWrapperHelper(:async_op);
55-
:async_op_error = dart.async::_asyncErrorWrapperHelper(:async_op);
56-
:async_completer.start(:async_op);
57-
return :async_completer.{dart.async::Completer::future};
58-
}
16+
static factory e4() → lib::C*
17+
let dynamic #redirecting_factory = lib::C::• in invalid-expression;
5918
}
19+
}
20+
library from "org-dartlang-test:///main.dart" as main {
21+
22+
import "org-dartlang-test:///lib.dart";
23+
6024
static method main() → void {
61-
main::C* c = main::C::e4();
25+
lib::C* c = new lib::C::();
6226
}
6327
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
main = <No Member>;
2+
library from "org-dartlang-test:///lib.dart" as lib {
3+
//
4+
// Problems in library:
5+
//
6+
// org-dartlang-test:///lib.dart:3:18: Error: Factory bodies can't use 'async', 'async*', or 'sync*'.
7+
// factory C.e4() async = C;
8+
// ^^^^^
9+
//
10+
11+
class C extends dart.core::Object {
12+
static field dynamic _redirecting# = <dynamic>[lib::C::e4];
13+
constructor •() → lib::C*
14+
: super dart.core::Object::•()
15+
;
16+
static factory e4() → lib::C*
17+
let dynamic #redirecting_factory = lib::C::• in invalid-expression;
18+
}
19+
}
20+
library from "org-dartlang-test:///main.dart" as main {
21+
22+
import "org-dartlang-test:///lib.dart";
23+
24+
static method main() → void {
25+
lib::C* c = new lib::C::•();
26+
dart.core::print(c);
27+
}
28+
}

0 commit comments

Comments
 (0)