Skip to content

Commit 0c5d46b

Browse files
eernstgCommit Queue
authored andcommitted
Add language test on spec change in dart-lang/language#4210
Change-Id: I0731af5cc96757f6beb7ef3e2434d50dfa48c2bb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/447800 Commit-Queue: Erik Ernst <[email protected]> Reviewed-by: Lasse Nielsen <[email protected]>
1 parent e2fb9e7 commit 0c5d46b

File tree

2 files changed

+233
-0
lines changed

2 files changed

+233
-0
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Dart 3.10 adds [dot shorthands][dot-shorthand-spec] to the language. To use
88
them, set your package's [SDK constraint][language version] lower bound to 3.10
99
or greater (`sdk: '^3.10.0'`).
1010

11+
Dart 3.10 also adjusts the inferred return type of a generator function (`sync*`
12+
or `async*`) to avoid introducing unneeded nullability.
13+
1114
#### Dot shorthands
1215

1316
Dot shorthands allow you to omit the type name when accessing a static member
@@ -40,6 +43,26 @@ To learn more about the feature, check out the
4043

4144
[dot-shorthand-spec]: https://github.com/dart-lang/language/blob/main/working/3616%20-%20enum%20value%20shorthand/proposal-simple-lrhn.md
4245

46+
#### Eliminate spurious Null from generator return type
47+
48+
The following local function `f` used to have return type `Iterable<int?>`.
49+
The question mark in this type is spurious because the returned iterable
50+
will never contain null (`return;` stops the iteration, it does not add null
51+
to the iterable). This feature makes the return type `Iterable<int>`.
52+
53+
```dart
54+
void main() {
55+
f() sync* {
56+
yield 1;
57+
return;
58+
}
59+
}
60+
```
61+
62+
This change may cause some code elements to be flagged as unnecessary. For
63+
example, `f().first?.isEven` is flagged, and `f().first.isEven` is recommended
64+
instead.
65+
4366
### Tools
4467

4568
#### Analyzer
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
// Copyright (c) 2025, 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+
// Regression test for https://github.com/dart-lang/language/pull/4210.
6+
7+
// ignore_for_file: unused_element
8+
9+
import '../static_type_helper.dart';
10+
11+
void testLocalFunctions() {
12+
withoutReturnSync() sync* {
13+
yield 1;
14+
}
15+
16+
withoutReturnSync.expectStaticType<Exactly<Iterable<int> Function()>>();
17+
withoutReturnSync().expectStaticType<Exactly<Iterable<int>>>();
18+
19+
withReturnSync() sync* {
20+
yield 1;
21+
return;
22+
}
23+
24+
// `return;` should not make the element type nullable.
25+
withReturnSync.expectStaticType<Exactly<Iterable<int> Function()>>();
26+
withReturnSync().expectStaticType<Exactly<Iterable<int>>>();
27+
28+
// No compile-time error occurs when the return type is declared.
29+
Iterable<int> withReturnSync2() sync* {
30+
yield 1;
31+
return;
32+
}
33+
34+
withReturnSync2.expectStaticType<Exactly<Iterable<int> Function()>>();
35+
withReturnSync2().expectStaticType<Exactly<Iterable<int>>>();
36+
37+
withoutReturnAsync() async* {
38+
yield 1;
39+
}
40+
41+
withoutReturnAsync.expectStaticType<Exactly<Stream<int> Function()>>();
42+
withoutReturnAsync().expectStaticType<Exactly<Stream<int>>>();
43+
44+
withReturnAsync() async* {
45+
yield 1;
46+
return;
47+
}
48+
49+
// `return;` should not make the element type nullable.
50+
withReturnAsync.expectStaticType<Exactly<Stream<int> Function()>>();
51+
withReturnAsync().expectStaticType<Exactly<Stream<int>>>();
52+
53+
// No compile-time error occurs when the return type is declared.
54+
Stream<int> withReturnAsync2() async* {
55+
yield 1;
56+
return;
57+
}
58+
59+
withReturnAsync2.expectStaticType<Exactly<Stream<int> Function()>>();
60+
withReturnAsync2().expectStaticType<Exactly<Stream<int>>>();
61+
62+
withoutReturnGenericSync<X>() sync* {
63+
yield 1 as X;
64+
}
65+
66+
withoutReturnGenericSync
67+
.expectStaticType<Exactly<Iterable<X> Function<X>()>>();
68+
withoutReturnGenericSync<int>().expectStaticType<Exactly<Iterable<int>>>();
69+
70+
withReturnGenericSync<X>() sync* {
71+
yield 1 as X;
72+
return;
73+
}
74+
75+
// `return;` should not make the element type nullable.
76+
withReturnGenericSync.expectStaticType<Exactly<Iterable<X> Function<X>()>>();
77+
withReturnGenericSync<int>().expectStaticType<Exactly<Iterable<int>>>();
78+
79+
// No compile-time error occurs when the return type is declared.
80+
Iterable<X> withReturnGenericSync2<X>() sync* {
81+
yield 1 as X;
82+
return;
83+
}
84+
85+
withReturnGenericSync2.expectStaticType<Exactly<Iterable<X> Function<X>()>>();
86+
withReturnGenericSync2<int>().expectStaticType<Exactly<Iterable<int>>>();
87+
88+
withoutReturnGenericAsync<X>() async* {
89+
yield 1 as X;
90+
}
91+
92+
withoutReturnGenericAsync
93+
.expectStaticType<Exactly<Stream<X> Function<X>()>>();
94+
withoutReturnGenericAsync<int>().expectStaticType<Exactly<Stream<int>>>();
95+
96+
withReturnGenericAsync<X>() async* {
97+
yield 1 as X;
98+
return;
99+
}
100+
101+
// `return;` should not make the element type nullable.
102+
withReturnGenericAsync.expectStaticType<Exactly<Stream<X> Function<X>()>>();
103+
withReturnGenericAsync<int>().expectStaticType<Exactly<Stream<int>>>();
104+
105+
// No compile-time error occurs when the return type is declared.
106+
Stream<X> withReturnGenericAsync2<X>() async* {
107+
yield 1 as X;
108+
return;
109+
}
110+
111+
withReturnGenericAsync2.expectStaticType<Exactly<Stream<X> Function<X>()>>();
112+
withReturnGenericAsync2<int>().expectStaticType<Exactly<Stream<int>>>();
113+
}
114+
115+
void testFunctionLiterals() {
116+
final withoutReturnSync = () sync* {
117+
yield 1;
118+
};
119+
withoutReturnSync.expectStaticType<Exactly<Iterable<int> Function()>>();
120+
withoutReturnSync().expectStaticType<Exactly<Iterable<int>>>();
121+
122+
final withReturnSync = () sync* {
123+
yield 1;
124+
return;
125+
};
126+
// `return;` should not make the element type nullable.
127+
withReturnSync.expectStaticType<Exactly<Iterable<int> Function()>>();
128+
withReturnSync().expectStaticType<Exactly<Iterable<int>>>();
129+
130+
// No compile-time error occurs when the return type is declared.
131+
final Iterable<int> Function() withReturnSync2 = () sync* {
132+
yield 1;
133+
return;
134+
};
135+
withReturnSync2.expectStaticType<Exactly<Iterable<int> Function()>>();
136+
withReturnSync2().expectStaticType<Exactly<Iterable<int>>>();
137+
138+
final withoutReturnAsync = () async* {
139+
yield 1;
140+
};
141+
withoutReturnAsync.expectStaticType<Exactly<Stream<int> Function()>>();
142+
withoutReturnAsync().expectStaticType<Exactly<Stream<int>>>();
143+
144+
final withReturnAsync = () async* {
145+
yield 1;
146+
return;
147+
};
148+
// `return;` should not make the element type nullable.
149+
withReturnAsync.expectStaticType<Exactly<Stream<int> Function()>>();
150+
withReturnAsync().expectStaticType<Exactly<Stream<int>>>();
151+
152+
// No compile-time error occers when the return type is declared.
153+
final Stream<int> Function() withReturnAsync2 = () async* {
154+
yield 1;
155+
return;
156+
};
157+
withReturnAsync2.expectStaticType<Exactly<Stream<int> Function()>>();
158+
withReturnAsync2().expectStaticType<Exactly<Stream<int>>>();
159+
160+
final withoutReturnGenericSync = <X>() sync* {
161+
yield 1 as X;
162+
};
163+
withoutReturnGenericSync
164+
.expectStaticType<Exactly<Iterable<X> Function<X>()>>();
165+
withoutReturnGenericSync<int>().expectStaticType<Exactly<Iterable<int>>>();
166+
167+
final withReturnGenericSync = <X>() sync* {
168+
yield 1 as X;
169+
return;
170+
};
171+
// `return;` should not make the element type nullable.
172+
withReturnGenericSync.expectStaticType<Exactly<Iterable<X> Function<X>()>>();
173+
withReturnGenericSync<int>().expectStaticType<Exactly<Iterable<int>>>();
174+
175+
// No compile-time error occurs when the return type is declared.
176+
final Iterable<X> Function<X>() withReturnGenericSync2 = <X>() sync* {
177+
yield 1 as X;
178+
return;
179+
};
180+
withReturnGenericSync2.expectStaticType<Exactly<Iterable<X> Function<X>()>>();
181+
withReturnGenericSync2<int>().expectStaticType<Exactly<Iterable<int>>>();
182+
183+
final withoutReturnGenericAsync = <X>() async* {
184+
yield 1 as X;
185+
};
186+
withoutReturnGenericAsync
187+
.expectStaticType<Exactly<Stream<X> Function<X>()>>();
188+
withoutReturnGenericAsync<int>().expectStaticType<Exactly<Stream<int>>>();
189+
190+
final withReturnGenericAsync = <X>() async* {
191+
yield 1 as X;
192+
return;
193+
};
194+
// `return;` should not make the element type nullable.
195+
withReturnGenericAsync.expectStaticType<Exactly<Stream<X> Function<X>()>>();
196+
withReturnGenericAsync<int>().expectStaticType<Exactly<Stream<int>>>();
197+
198+
// No compile-time error occers when the return type is declared.
199+
final Stream<X> Function<X>() withReturnGenericAsync2 = <X>() async* {
200+
yield 1 as X;
201+
return;
202+
};
203+
withReturnGenericAsync2.expectStaticType<Exactly<Stream<X> Function<X>()>>();
204+
withReturnGenericAsync2<int>().expectStaticType<Exactly<Stream<int>>>();
205+
}
206+
207+
void main() {
208+
testLocalFunctions();
209+
testFunctionLiterals();
210+
}

0 commit comments

Comments
 (0)