Skip to content

Commit d74965e

Browse files
johnniwintherCommit Queue
authored andcommitted
[cfe] Check inline class constructor initializers
Change-Id: I6872ccd948f679e1e0b04b9f59bea833df11d5a2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/277141 Reviewed-by: Chloe Stefantsova <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 851332b commit d74965e

36 files changed

+942
-277
lines changed

pkg/front_end/lib/src/fasta/kernel/kernel_target.dart

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import '../source/constructor_declaration.dart';
6868
import '../source/source_class_builder.dart' show SourceClassBuilder;
6969
import '../source/source_constructor_builder.dart';
7070
import '../source/source_field_builder.dart';
71+
import '../source/source_inline_class_builder.dart';
7172
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
7273
import '../source/source_loader.dart' show SourceLoader;
7374
import '../target_implementation.dart' show TargetImplementation;
@@ -620,7 +621,9 @@ class KernelTarget extends TargetImplementation {
620621
loader.finishNoSuchMethodForwarders();
621622

622623
benchmarker?.enterPhase(BenchmarkPhases.body_collectSourceClasses);
623-
List<SourceClassBuilder>? sourceClasses = loader.collectSourceClasses();
624+
List<SourceClassBuilder>? sourceClasses = [];
625+
List<SourceInlineClassBuilder>? inlineClasses = [];
626+
loader.collectSourceClasses(sourceClasses, inlineClasses);
624627

625628
benchmarker?.enterPhase(BenchmarkPhases.body_finishNativeMethods);
626629
loader.finishNativeMethods();
@@ -629,7 +632,7 @@ class KernelTarget extends TargetImplementation {
629632
loader.buildBodyNodes();
630633

631634
benchmarker?.enterPhase(BenchmarkPhases.body_finishAllConstructors);
632-
finishAllConstructors(sourceClasses);
635+
finishAllConstructors(sourceClasses, inlineClasses);
633636

634637
benchmarker?.enterPhase(BenchmarkPhases.body_runBuildTransformations);
635638
runBuildTransformations();
@@ -649,6 +652,7 @@ class KernelTarget extends TargetImplementation {
649652
// (for whatever amount of time) even though we convert them to dill
650653
// library builders. To avoid it we null it out here.
651654
sourceClasses = null;
655+
inlineClasses = null;
652656
return new BuildResult(
653657
component: component, macroApplications: macroApplications);
654658
}, () => loader.currentUriForCrashReporting);
@@ -1244,22 +1248,27 @@ class KernelTarget extends TargetImplementation {
12441248
loader.computeCoreTypes(platformLibraries);
12451249
}
12461250

1247-
void finishAllConstructors(List<SourceClassBuilder> builders) {
1251+
void finishAllConstructors(List<SourceClassBuilder> sourceClassBuilders,
1252+
List<SourceInlineClassBuilder> inlineClassBuilders) {
12481253
Class objectClass = this.objectClass;
1249-
for (SourceClassBuilder builder in builders) {
1254+
for (SourceClassBuilder builder in sourceClassBuilders) {
12501255
Class cls = builder.cls;
12511256
if (cls != objectClass) {
12521257
finishConstructors(builder);
12531258
}
12541259
}
1260+
for (SourceInlineClassBuilder builder in inlineClassBuilders) {
1261+
finishInlineConstructors(builder);
1262+
}
1263+
12551264
ticker.logMs("Finished constructors");
12561265
}
12571266

1258-
/// Ensure constructors of [builder] have the correct initializers and other
1259-
/// requirements.
1260-
void finishConstructors(SourceClassBuilder builder) {
1261-
if (builder.isPatch) return;
1262-
Class cls = builder.cls;
1267+
/// Ensure constructors of [classBuilder] have the correct initializers and
1268+
/// other requirements.
1269+
void finishConstructors(SourceClassBuilder classBuilder) {
1270+
if (classBuilder.isPatch) return;
1271+
Class cls = classBuilder.cls;
12631272

12641273
Constructor? superTarget;
12651274
for (Constructor constructor in cls.constructors) {
@@ -1270,8 +1279,10 @@ class KernelTarget extends TargetImplementation {
12701279
for (Initializer initializer in constructor.initializers) {
12711280
if (initializer is RedirectingInitializer) {
12721281
if (constructor.isConst && !initializer.target.isConst) {
1273-
builder.addProblem(messageConstConstructorRedirectionToNonConst,
1274-
initializer.fileOffset, initializer.target.name.text.length);
1282+
classBuilder.addProblem(
1283+
messageConstConstructorRedirectionToNonConst,
1284+
initializer.fileOffset,
1285+
initializer.target.name.text.length);
12751286
}
12761287
isRedirecting = true;
12771288
break;
@@ -1289,7 +1300,7 @@ class KernelTarget extends TargetImplementation {
12891300
if (offset == -1 && constructor.isSynthetic) {
12901301
offset = cls.fileOffset;
12911302
}
1292-
builder.addProblem(
1303+
classBuilder.addProblem(
12931304
templateSuperclassHasNoDefaultConstructor
12941305
.withArguments(cls.superclass!.name),
12951306
offset,
@@ -1313,11 +1324,15 @@ class KernelTarget extends TargetImplementation {
13131324
}
13141325
}
13151326

1316-
finishConstructorsInternal(builder);
1327+
_finishConstructors(classBuilder);
1328+
}
1329+
1330+
void finishInlineConstructors(SourceInlineClassBuilder inlineClass) {
1331+
_finishConstructors(inlineClass);
13171332
}
13181333

1319-
void finishConstructorsInternal(ClassDeclaration builder) {
1320-
SourceLibraryBuilder libraryBuilder = builder.libraryBuilder;
1334+
void _finishConstructors(ClassDeclaration classDeclaration) {
1335+
SourceLibraryBuilder libraryBuilder = classDeclaration.libraryBuilder;
13211336

13221337
/// Quotes below are from [Dart Programming Language Specification, 4th
13231338
/// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
@@ -1326,7 +1341,7 @@ class KernelTarget extends TargetImplementation {
13261341
List<SourceFieldBuilder> lateFinalFields = [];
13271342

13281343
Iterator<SourceFieldBuilder> fieldIterator =
1329-
builder.fullMemberIterator<SourceFieldBuilder>();
1344+
classDeclaration.fullMemberIterator<SourceFieldBuilder>();
13301345
while (fieldIterator.moveNext()) {
13311346
SourceFieldBuilder fieldBuilder = fieldIterator.current;
13321347
if (fieldBuilder.isAbstract || fieldBuilder.isExternal) {
@@ -1352,12 +1367,12 @@ class KernelTarget extends TargetImplementation {
13521367
Set<SourceFieldBuilder>? initializedFieldBuilders = null;
13531368

13541369
Iterator<ConstructorDeclaration> constructorIterator =
1355-
builder.fullConstructorIterator<ConstructorDeclaration>();
1370+
classDeclaration.fullConstructorIterator<ConstructorDeclaration>();
13561371
while (constructorIterator.moveNext()) {
13571372
ConstructorDeclaration constructor = constructorIterator.current;
13581373
if (constructor.isEffectivelyRedirecting) continue;
13591374
if (constructor.isConst && nonFinalFields.isNotEmpty) {
1360-
builder.addProblem(messageConstConstructorNonFinalField,
1375+
classDeclaration.addProblem(messageConstConstructorNonFinalField,
13611376
constructor.charOffset, noLength,
13621377
context: nonFinalFields
13631378
.map((field) => messageConstConstructorNonFinalFieldCause
@@ -1368,8 +1383,10 @@ class KernelTarget extends TargetImplementation {
13681383
if (libraryBuilder.isNonNullableByDefault) {
13691384
if (constructor.isConst && lateFinalFields.isNotEmpty) {
13701385
for (FieldBuilder field in lateFinalFields) {
1371-
builder.addProblem(messageConstConstructorLateFinalFieldError,
1372-
field.charOffset, noLength,
1386+
classDeclaration.addProblem(
1387+
messageConstConstructorLateFinalFieldError,
1388+
field.charOffset,
1389+
noLength,
13731390
context: [
13741391
messageConstConstructorLateFinalFieldCause.withLocation(
13751392
constructor.fileUri!, constructor.charOffset, noLength)
@@ -1393,8 +1410,8 @@ class KernelTarget extends TargetImplementation {
13931410
!initializedFieldBuilders.contains(fieldBuilder)) {
13941411
bool uninitializedFinalOrNonNullableFieldIsError =
13951412
libraryBuilder.isNonNullableByDefault ||
1396-
builder.hasGenerativeConstructor ||
1397-
builder.isMixinDeclaration;
1413+
classDeclaration.hasGenerativeConstructor ||
1414+
classDeclaration.isMixinDeclaration;
13981415
if (!fieldBuilder.isLate) {
13991416
if (fieldBuilder.isFinal &&
14001417
uninitializedFinalOrNonNullableFieldIsError) {

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

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import '../builder/builder.dart';
56
import '../builder/class_builder.dart';
67
import '../builder/declaration_builder.dart';
8+
import '../builder/member_builder.dart';
9+
import '../builder/name_iterator.dart';
710
import 'source_library_builder.dart';
811

912
/// Common interface for builders for a class declarations in source code, such
@@ -19,3 +22,212 @@ abstract class ClassDeclaration
1922
/// either explicitly or implicitly through a no-name default constructor.
2023
bool get hasGenerativeConstructor;
2124
}
25+
26+
abstract class ClassDeclarationAugmentationAccess<D extends ClassDeclaration> {
27+
D getOrigin(D classDeclaration);
28+
Iterable<D>? getAugmentations(D classDeclaration);
29+
}
30+
31+
class ClassDeclarationMemberIterator<D extends ClassDeclaration,
32+
T extends Builder> implements Iterator<T> {
33+
Iterator<T>? _iterator;
34+
Iterator<D>? augmentationBuilders;
35+
final bool includeDuplicates;
36+
37+
factory ClassDeclarationMemberIterator(
38+
ClassDeclarationAugmentationAccess<D> patching, D classBuilder,
39+
{required bool includeDuplicates}) {
40+
return new ClassDeclarationMemberIterator._(
41+
patching.getOrigin(classBuilder),
42+
patching.getAugmentations(classBuilder)?.iterator,
43+
includeDuplicates: includeDuplicates);
44+
}
45+
46+
ClassDeclarationMemberIterator._(
47+
D classDeclaration, this.augmentationBuilders,
48+
{required this.includeDuplicates})
49+
: _iterator = classDeclaration.scope.filteredIterator<T>(
50+
parent: classDeclaration,
51+
includeDuplicates: includeDuplicates,
52+
includeAugmentations: false);
53+
54+
@override
55+
bool moveNext() {
56+
if (_iterator != null) {
57+
if (_iterator!.moveNext()) {
58+
return true;
59+
}
60+
}
61+
if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
62+
D augmentationClassDeclaration = augmentationBuilders!.current;
63+
_iterator = augmentationClassDeclaration.scope.filteredIterator<T>(
64+
parent: augmentationClassDeclaration,
65+
includeDuplicates: includeDuplicates,
66+
includeAugmentations: false);
67+
}
68+
if (_iterator != null) {
69+
if (_iterator!.moveNext()) {
70+
return true;
71+
}
72+
}
73+
return false;
74+
}
75+
76+
@override
77+
T get current => _iterator?.current ?? (throw new StateError('No element'));
78+
}
79+
80+
class ClassDeclarationMemberNameIterator<D extends ClassDeclaration,
81+
T extends Builder> implements NameIterator<T> {
82+
NameIterator<T>? _iterator;
83+
Iterator<D>? augmentationBuilders;
84+
final bool includeDuplicates;
85+
86+
factory ClassDeclarationMemberNameIterator(
87+
ClassDeclarationAugmentationAccess<D> patching, D classBuilder,
88+
{required bool includeDuplicates}) {
89+
return new ClassDeclarationMemberNameIterator._(
90+
patching.getOrigin(classBuilder),
91+
patching.getAugmentations(classBuilder)?.iterator,
92+
includeDuplicates: includeDuplicates);
93+
}
94+
95+
ClassDeclarationMemberNameIterator._(
96+
D classDeclaration, this.augmentationBuilders,
97+
{required this.includeDuplicates})
98+
: _iterator = classDeclaration.scope.filteredNameIterator<T>(
99+
parent: classDeclaration,
100+
includeDuplicates: includeDuplicates,
101+
includeAugmentations: false);
102+
103+
@override
104+
bool moveNext() {
105+
if (_iterator != null) {
106+
if (_iterator!.moveNext()) {
107+
return true;
108+
}
109+
}
110+
if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
111+
D augmentationClassDeclaration = augmentationBuilders!.current;
112+
_iterator = augmentationClassDeclaration.scope.filteredNameIterator<T>(
113+
parent: augmentationClassDeclaration,
114+
includeDuplicates: includeDuplicates,
115+
includeAugmentations: false);
116+
}
117+
if (_iterator != null) {
118+
if (_iterator!.moveNext()) {
119+
return true;
120+
}
121+
}
122+
return false;
123+
}
124+
125+
@override
126+
T get current => _iterator?.current ?? (throw new StateError('No element'));
127+
128+
@override
129+
String get name => _iterator?.name ?? (throw new StateError('No element'));
130+
}
131+
132+
class ClassDeclarationConstructorIterator<D extends ClassDeclaration,
133+
T extends MemberBuilder> implements Iterator<T> {
134+
Iterator<T>? _iterator;
135+
Iterator<D>? augmentationBuilders;
136+
final bool includeDuplicates;
137+
138+
factory ClassDeclarationConstructorIterator(
139+
ClassDeclarationAugmentationAccess<D> patching, D classBuilder,
140+
{required bool includeDuplicates}) {
141+
return new ClassDeclarationConstructorIterator._(
142+
patching.getOrigin(classBuilder),
143+
patching.getAugmentations(classBuilder)?.iterator,
144+
includeDuplicates: includeDuplicates);
145+
}
146+
147+
ClassDeclarationConstructorIterator._(
148+
D classDeclaration, this.augmentationBuilders,
149+
{required this.includeDuplicates})
150+
: _iterator = classDeclaration.constructorScope.filteredIterator<T>(
151+
parent: classDeclaration,
152+
includeDuplicates: includeDuplicates,
153+
includeAugmentations: false);
154+
155+
@override
156+
bool moveNext() {
157+
if (_iterator != null) {
158+
if (_iterator!.moveNext()) {
159+
return true;
160+
}
161+
}
162+
if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
163+
D augmentationClassDeclaration = augmentationBuilders!.current;
164+
_iterator = augmentationClassDeclaration.constructorScope
165+
.filteredIterator<T>(
166+
parent: augmentationClassDeclaration,
167+
includeDuplicates: includeDuplicates,
168+
includeAugmentations: false);
169+
}
170+
if (_iterator != null) {
171+
if (_iterator!.moveNext()) {
172+
return true;
173+
}
174+
}
175+
return false;
176+
}
177+
178+
@override
179+
T get current => _iterator?.current ?? (throw new StateError('No element'));
180+
}
181+
182+
class ClassDeclarationConstructorNameIterator<D extends ClassDeclaration,
183+
T extends MemberBuilder> implements NameIterator<T> {
184+
NameIterator<T>? _iterator;
185+
Iterator<D>? augmentationBuilders;
186+
final bool includeDuplicates;
187+
188+
factory ClassDeclarationConstructorNameIterator(
189+
ClassDeclarationAugmentationAccess<D> patching, D classDeclaration,
190+
{required bool includeDuplicates}) {
191+
return new ClassDeclarationConstructorNameIterator._(
192+
patching.getOrigin(classDeclaration),
193+
patching.getAugmentations(classDeclaration)?.iterator,
194+
includeDuplicates: includeDuplicates);
195+
}
196+
197+
ClassDeclarationConstructorNameIterator._(
198+
D classBuilder, this.augmentationBuilders,
199+
{required this.includeDuplicates})
200+
: _iterator = classBuilder.constructorScope.filteredNameIterator<T>(
201+
parent: classBuilder,
202+
includeDuplicates: includeDuplicates,
203+
includeAugmentations: false);
204+
205+
@override
206+
bool moveNext() {
207+
if (_iterator != null) {
208+
if (_iterator!.moveNext()) {
209+
return true;
210+
}
211+
}
212+
if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
213+
D augmentationClassDeclaration = augmentationBuilders!.current;
214+
_iterator = augmentationClassDeclaration.constructorScope
215+
.filteredNameIterator<T>(
216+
parent: augmentationClassDeclaration,
217+
includeDuplicates: includeDuplicates,
218+
includeAugmentations: false);
219+
}
220+
if (_iterator != null) {
221+
if (_iterator!.moveNext()) {
222+
return true;
223+
}
224+
}
225+
return false;
226+
}
227+
228+
@override
229+
T get current => _iterator?.current ?? (throw new StateError('No element'));
230+
231+
@override
232+
String get name => _iterator?.name ?? (throw new StateError('No element'));
233+
}

0 commit comments

Comments
 (0)