Skip to content

Commit 255f260

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Report error on await of extension type that is not a future
Closes #53207 Part of #49731 Change-Id: Idad31c3286108aa3dc75b4b3d7f5364674641582 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/331980 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 3659b3e commit 255f260

12 files changed

+960
-1
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

+11
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,17 @@ const MessageCode messageAwaitNotAsync = const MessageCode("AwaitNotAsync",
340340
problemMessage:
341341
r"""'await' can only be used in 'async' or 'async*' methods.""");
342342

343+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
344+
const Code<Null> codeAwaitOfExtensionTypeNotFuture =
345+
messageAwaitOfExtensionTypeNotFuture;
346+
347+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
348+
const MessageCode messageAwaitOfExtensionTypeNotFuture = const MessageCode(
349+
"AwaitOfExtensionTypeNotFuture",
350+
analyzerCodes: <String>["AWAIT_OF_EXTENSION_TYPE_NOT_FUTURE"],
351+
problemMessage:
352+
r"""The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.""");
353+
343354
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
344355
const Template<
345356
Message Function(

pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart

+13-1
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,19 @@ class InferenceVisitorImpl extends InferenceVisitorBase
814814
isVoidAllowed: !isNonNullableByDefault);
815815
DartType operandType = operandResult.inferredType;
816816
DartType flattenType = typeSchemaEnvironment.flatten(operandType);
817-
node.operand = operandResult.expression..parent = node;
817+
if (operandType is ExtensionType &&
818+
typeSchemaEnvironment.hierarchy.getExtensionTypeAsInstanceOfClass(
819+
operandType, coreTypes.futureClass,
820+
isNonNullableByDefault:
821+
libraryBuilder.isNonNullableByDefault) ==
822+
null) {
823+
Expression wrapped = operandResult.expression;
824+
node.operand = helper.wrapInProblem(
825+
wrapped, messageAwaitOfExtensionTypeNotFuture, wrapped.fileOffset, 1);
826+
wrapped.parent = node.operand;
827+
} else {
828+
node.operand = operandResult.expression..parent = node;
829+
}
818830
DartType runtimeCheckType = new InterfaceType(
819831
coreTypes.futureClass, libraryBuilder.nonNullable, [flattenType]);
820832
if (!typeSchemaEnvironment.isSubtypeOf(

pkg/front_end/messages.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -7461,3 +7461,10 @@ WrongTypeParameterVarianceInSuperinterface:
74617461
script: |
74627462
extension type E<X>(List<Function(Object?)> foo) implements List<Function(X)> {}
74637463
analyzerCode: WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
7464+
7465+
AwaitOfExtensionTypeNotFuture:
7466+
problemMessage: "The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'."
7467+
experiments: inline-class
7468+
script: |
7469+
extension type E(num foo) { test(E e) async { await e; } }
7470+
analyzerCode: AWAIT_OF_EXTENSION_TYPE_NOT_FUTURE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
import 'dart:async';
6+
7+
extension type E1(Future<int> foo) {}
8+
extension type E2<X extends Future<String>>(X foo) {}
9+
extension type E3(FutureOr<bool> foo) {}
10+
extension type E4<X extends FutureOr<double>>(X foo) {}
11+
extension type E5<X>(X foo) {}
12+
13+
extension type F1(Future<int> foo) implements Future<int> {}
14+
extension type F2<X extends Future<num>>(X foo) implements Future<num> {}
15+
extension type F3<X extends Future<Object>>(X foo) implements Future<Object> {}
16+
extension type F4<X extends Future<num>>(X foo) implements F3<X> {}
17+
18+
test(
19+
E1 e1, E2<Future<String>> e2, E3 e3, E4<Future<double>> e4, E5<Object> e5object, E5<Future<num>> e5future,
20+
F1 f1, F2<Future<num>> f2, F3<Future<String>> f3, F4<Future<int>> f4) async {
21+
await e1; // Error.
22+
await e2; // Error.
23+
await e3; // Error.
24+
await e4; // Error.
25+
await e5object; // Error.
26+
await e5future; // Error.
27+
28+
await f1; // Ok.
29+
await f2; // Ok.
30+
await f3; // Ok.
31+
await f4; // Ok.
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/extension_types/issue53207.dart:21:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
6+
// await e1; // Error.
7+
// ^
8+
//
9+
// pkg/front_end/testcases/extension_types/issue53207.dart:22:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
10+
// await e2; // Error.
11+
// ^
12+
//
13+
// pkg/front_end/testcases/extension_types/issue53207.dart:23:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
14+
// await e3; // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/extension_types/issue53207.dart:24:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
18+
// await e4; // Error.
19+
// ^
20+
//
21+
// pkg/front_end/testcases/extension_types/issue53207.dart:25:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
22+
// await e5object; // Error.
23+
// ^
24+
//
25+
// pkg/front_end/testcases/extension_types/issue53207.dart:26:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
26+
// await e5future; // Error.
27+
// ^
28+
//
29+
import self as self;
30+
import "dart:async" as asy;
31+
import "dart:core" as core;
32+
33+
import "dart:async";
34+
35+
extension type E1(asy::Future<core::int> foo) {
36+
abstract inline-class-member representation-field get foo() → asy::Future<core::int>;
37+
constructor • = self::E1|constructor#;
38+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
39+
}
40+
extension type E2<X extends asy::Future<core::String>>(X foo) {
41+
abstract inline-class-member representation-field get foo() → X;
42+
constructor • = self::E2|constructor#;
43+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
44+
}
45+
extension type E3(FutureOr<core::bool>foo) {
46+
abstract inline-class-member representation-field get foo() → FutureOr<core::bool>;
47+
constructor • = self::E3|constructor#;
48+
constructor tearoff • = self::E3|constructor#_#new#tearOff;
49+
}
50+
extension type E4<X extends FutureOr<core::double>>(X foo) {
51+
abstract inline-class-member representation-field get foo() → X;
52+
constructor • = self::E4|constructor#;
53+
constructor tearoff • = self::E4|constructor#_#new#tearOff;
54+
}
55+
extension type E5<X extends core::Object? = dynamic>(X% foo) {
56+
abstract inline-class-member representation-field get foo() → X%;
57+
constructor • = self::E5|constructor#;
58+
constructor tearoff • = self::E5|constructor#_#new#tearOff;
59+
}
60+
extension type F1(asy::Future<core::int> foo) implements asy::Future<core::int> {
61+
abstract inline-class-member representation-field get foo() → asy::Future<core::int>;
62+
constructor • = self::F1|constructor#;
63+
constructor tearoff • = self::F1|constructor#_#new#tearOff;
64+
}
65+
extension type F2<X extends asy::Future<core::num>>(X foo) implements asy::Future<core::num> {
66+
abstract inline-class-member representation-field get foo() → X;
67+
constructor • = self::F2|constructor#;
68+
constructor tearoff • = self::F2|constructor#_#new#tearOff;
69+
}
70+
extension type F3<X extends asy::Future<core::Object>>(X foo) implements asy::Future<core::Object> {
71+
abstract inline-class-member representation-field get foo() → X;
72+
constructor • = self::F3|constructor#;
73+
constructor tearoff • = self::F3|constructor#_#new#tearOff;
74+
}
75+
extension type F4<X extends asy::Future<core::num>>(X foo) implements self::F3<X> /* = X */ {
76+
abstract inline-class-member representation-field get foo() → X;
77+
constructor • = self::F4|constructor#;
78+
constructor tearoff • = self::F4|constructor#_#new#tearOff;
79+
}
80+
static inline-class-member method E1|constructor#(asy::Future<core::int> foo) → self::E1 /* = asy::Future<core::int> */ {
81+
lowered final self::E1 /* = asy::Future<core::int> */ #this = foo;
82+
return #this;
83+
}
84+
static inline-class-member method E1|constructor#_#new#tearOff(asy::Future<core::int> foo) → self::E1 /* = asy::Future<core::int> */
85+
return self::E1|constructor#(foo);
86+
static inline-class-member method E2|constructor#<X extends asy::Future<core::String>>(self::E2|constructor#::X foo) → self::E2<self::E2|constructor#::X> /* = self::E2|constructor#::X */ {
87+
lowered final self::E2<self::E2|constructor#::X> /* = self::E2|constructor#::X */ #this = foo;
88+
return #this;
89+
}
90+
static inline-class-member method E2|constructor#_#new#tearOff<X extends asy::Future<core::String>>(self::E2|constructor#_#new#tearOff::X foo) → self::E2<self::E2|constructor#_#new#tearOff::X> /* = self::E2|constructor#_#new#tearOff::X */
91+
return self::E2|constructor#<self::E2|constructor#_#new#tearOff::X>(foo);
92+
static inline-class-member method E3|constructor#(FutureOr<core::bool>foo) → self::E3 /* = FutureOr<core::bool>*/ {
93+
lowered final self::E3 /* = FutureOr<core::bool>*/ #this = foo;
94+
return #this;
95+
}
96+
static inline-class-member method E3|constructor#_#new#tearOff(FutureOr<core::bool>foo) → self::E3 /* = FutureOr<core::bool>*/
97+
return self::E3|constructor#(foo);
98+
static inline-class-member method E4|constructor#<X extends FutureOr<core::double>>(self::E4|constructor#::X foo) → self::E4<self::E4|constructor#::X> /* = self::E4|constructor#::X */ {
99+
lowered final self::E4<self::E4|constructor#::X> /* = self::E4|constructor#::X */ #this = foo;
100+
return #this;
101+
}
102+
static inline-class-member method E4|constructor#_#new#tearOff<X extends FutureOr<core::double>>(self::E4|constructor#_#new#tearOff::X foo) → self::E4<self::E4|constructor#_#new#tearOff::X> /* = self::E4|constructor#_#new#tearOff::X */
103+
return self::E4|constructor#<self::E4|constructor#_#new#tearOff::X>(foo);
104+
static inline-class-member method E5|constructor#<X extends core::Object? = dynamic>(self::E5|constructor#::X% foo) → self::E5<self::E5|constructor#::X%> /* = self::E5|constructor#::X% */ {
105+
lowered final self::E5<self::E5|constructor#::X%> /* = self::E5|constructor#::X% */ #this = foo;
106+
return #this;
107+
}
108+
static inline-class-member method E5|constructor#_#new#tearOff<X extends core::Object? = dynamic>(self::E5|constructor#_#new#tearOff::X% foo) → self::E5<self::E5|constructor#_#new#tearOff::X%>% /* = self::E5|constructor#_#new#tearOff::X% */
109+
return self::E5|constructor#<self::E5|constructor#_#new#tearOff::X%>(foo);
110+
static inline-class-member method F1|constructor#(asy::Future<core::int> foo) → self::F1 /* = asy::Future<core::int> */ {
111+
lowered final self::F1 /* = asy::Future<core::int> */ #this = foo;
112+
return #this;
113+
}
114+
static inline-class-member method F1|constructor#_#new#tearOff(asy::Future<core::int> foo) → self::F1 /* = asy::Future<core::int> */
115+
return self::F1|constructor#(foo);
116+
static inline-class-member method F2|constructor#<X extends asy::Future<core::num>>(self::F2|constructor#::X foo) → self::F2<self::F2|constructor#::X> /* = self::F2|constructor#::X */ {
117+
lowered final self::F2<self::F2|constructor#::X> /* = self::F2|constructor#::X */ #this = foo;
118+
return #this;
119+
}
120+
static inline-class-member method F2|constructor#_#new#tearOff<X extends asy::Future<core::num>>(self::F2|constructor#_#new#tearOff::X foo) → self::F2<self::F2|constructor#_#new#tearOff::X> /* = self::F2|constructor#_#new#tearOff::X */
121+
return self::F2|constructor#<self::F2|constructor#_#new#tearOff::X>(foo);
122+
static inline-class-member method F3|constructor#<X extends asy::Future<core::Object>>(self::F3|constructor#::X foo) → self::F3<self::F3|constructor#::X> /* = self::F3|constructor#::X */ {
123+
lowered final self::F3<self::F3|constructor#::X> /* = self::F3|constructor#::X */ #this = foo;
124+
return #this;
125+
}
126+
static inline-class-member method F3|constructor#_#new#tearOff<X extends asy::Future<core::Object>>(self::F3|constructor#_#new#tearOff::X foo) → self::F3<self::F3|constructor#_#new#tearOff::X> /* = self::F3|constructor#_#new#tearOff::X */
127+
return self::F3|constructor#<self::F3|constructor#_#new#tearOff::X>(foo);
128+
static inline-class-member method F4|constructor#<X extends asy::Future<core::num>>(self::F4|constructor#::X foo) → self::F4<self::F4|constructor#::X> /* = self::F4|constructor#::X */ {
129+
lowered final self::F4<self::F4|constructor#::X> /* = self::F4|constructor#::X */ #this = foo;
130+
return #this;
131+
}
132+
static inline-class-member method F4|constructor#_#new#tearOff<X extends asy::Future<core::num>>(self::F4|constructor#_#new#tearOff::X foo) → self::F4<self::F4|constructor#_#new#tearOff::X> /* = self::F4|constructor#_#new#tearOff::X */
133+
return self::F4|constructor#<self::F4|constructor#_#new#tearOff::X>(foo);
134+
static method test(self::E1 /* = asy::Future<core::int> */ e1, self::E2<asy::Future<core::String>> /* = asy::Future<core::String> */ e2, self::E3 /* = FutureOr<core::bool>*/ e3, self::E4<asy::Future<core::double>> /* = asy::Future<core::double> */ e4, self::E5<core::Object> /* = core::Object */ e5object, self::E5<asy::Future<core::num>> /* = asy::Future<core::num> */ e5future, self::F1 /* = asy::Future<core::int> */ f1, self::F2<asy::Future<core::num>> /* = asy::Future<core::num> */ f2, self::F3<asy::Future<core::String>> /* = asy::Future<core::String> */ f3, self::F4<asy::Future<core::int>> /* = asy::Future<core::int> */ f4) → dynamic async /* futureValueType= dynamic */ {
135+
await invalid-expression "pkg/front_end/testcases/extension_types/issue53207.dart:21:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
136+
await e1; // Error.
137+
^" in e1 /* runtimeCheckType= asy::Future<core::int> */ ;
138+
await invalid-expression "pkg/front_end/testcases/extension_types/issue53207.dart:22:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
139+
await e2; // Error.
140+
^" in e2 /* runtimeCheckType= asy::Future<core::String> */ ;
141+
await invalid-expression "pkg/front_end/testcases/extension_types/issue53207.dart:23:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
142+
await e3; // Error.
143+
^" in e3 /* runtimeCheckType= asy::Future<core::bool> */ ;
144+
await invalid-expression "pkg/front_end/testcases/extension_types/issue53207.dart:24:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
145+
await e4; // Error.
146+
^" in e4 /* runtimeCheckType= asy::Future<core::double> */ ;
147+
await invalid-expression "pkg/front_end/testcases/extension_types/issue53207.dart:25:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
148+
await e5object; // Error.
149+
^" in e5object /* runtimeCheckType= asy::Future<self::E5<core::Object> /* = core::Object */> */ ;
150+
await invalid-expression "pkg/front_end/testcases/extension_types/issue53207.dart:26:9: Error: The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'.
151+
await e5future; // Error.
152+
^" in e5future /* runtimeCheckType= asy::Future<core::num> */ ;
153+
await f1;
154+
await f2;
155+
await f3 /* runtimeCheckType= asy::Future<core::String> */ ;
156+
await f4 /* runtimeCheckType= asy::Future<core::int> */ ;
157+
}

0 commit comments

Comments
 (0)