Skip to content

Commit 41e983d

Browse files
scheglovCommit Queue
authored andcommitted
Fine. Track hasNonFinalField in manifests and requirements.
Persist and track `hasNonFinalField` for interface-like elements so fine- grained dependencies can invalidate precisely when a class (or its supertypes) declares a non-final instance field. What’s changed - Store `hasNonFinalField` on manifest items for classes, enums, extension types, and mixins. The flag is serialized/deserialized and printed in dumps. - Add a tracked getter on `InterfaceElementImpl` that records a dependency when `hasNonFinalField` is queried; use a private backing field with a setter. - Extend requirements schema with an optional `hasNonFinalField` entry and record it when requested. - Validate the requirement via a new `InterfaceHasNonFinalFieldMismatch` failure. - Exclude `hasNonFinalField` from item identity matching; it is enforced via requirements instead of forcing new IDs. - Bump `AnalysisDriver.DATA_VERSION` to 541 for the format change. Why - Consumers that depend on mutability of instance fields (directly or through inheritance) now get targeted invalidation without unnecessary ID churn, improving both correctness and incremental performance. Implementation notes - LibraryManifestBuilder copies `element.hasNonFinalField` into item instances. - Manifest read/write gains a boolean field on `InterfaceItem` (and subclasses) and helpers to encode/decode optional booleans in the requirements stream. - Result printer includes `hasNonFinalField` in interface requirement dumps. Change-Id: Ib132dca582f77df87f995920dd9b73784a4eeefd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448444 Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent acc4ee0 commit 41e983d

File tree

8 files changed

+715
-3
lines changed

8 files changed

+715
-3
lines changed

pkg/analyzer/lib/src/dart/analysis/driver.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ testFineAfterLibraryAnalyzerHook;
106106
// TODO(scheglov): Clean up the list of implicitly analyzed files.
107107
class AnalysisDriver {
108108
/// The version of data format, should be incremented on every format change.
109-
static const int DATA_VERSION = 539;
109+
static const int DATA_VERSION = 541;
110110

111111
/// The number of exception contexts allowed to write. Once this field is
112112
/// zero, we stop writing any new exception contexts in this process.

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4646,8 +4646,8 @@ abstract class InterfaceElementImpl extends InstanceElementImpl
46464646
List<InterfaceTypeImpl>? Function(InterfaceElementImpl)?
46474647
mixinInferenceCallback;
46484648

4649-
/// Whether the class or its superclass declares a non-final instance field.
4650-
bool hasNonFinalField = false;
4649+
/// Storage for [hasNonFinalField].
4650+
bool _hasNonFinalField = false;
46514651

46524652
@override
46534653
List<InterfaceTypeImpl> get allSupertypes {
@@ -4705,6 +4705,19 @@ abstract class InterfaceElementImpl extends InstanceElementImpl
47054705
];
47064706
}
47074707

4708+
/// Whether the class or its superclass declares a non-final instance field.
4709+
@trackedDirectly
4710+
bool get hasNonFinalField {
4711+
globalResultRequirements?.record_interfaceElement_hasNonFinalField(
4712+
element: this,
4713+
);
4714+
return _hasNonFinalField;
4715+
}
4716+
4717+
set hasNonFinalField(bool value) {
4718+
_hasNonFinalField = value;
4719+
}
4720+
47084721
InheritanceManager3 get inheritanceManager {
47094722
return library.session.inheritanceManager;
47104723
}

pkg/analyzer/lib/src/fine/library_manifest.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ class LibraryManifestBuilder {
216216
element: element,
217217
);
218218
});
219+
classItem.hasNonFinalField = element.hasNonFinalField;
219220
newItems[lookupName] = classItem;
220221

221222
encodingContext.withTypeParameters(element.typeParameters, (
@@ -301,6 +302,7 @@ class LibraryManifestBuilder {
301302
element: element,
302303
);
303304
});
305+
enumItem.hasNonFinalField = element.hasNonFinalField;
304306
newItems[lookupName] = enumItem;
305307

306308
encodingContext.withTypeParameters(element.typeParameters, (
@@ -380,6 +382,7 @@ class LibraryManifestBuilder {
380382
element: element,
381383
);
382384
});
385+
extensionTypeItem.hasNonFinalField = element.hasNonFinalField;
383386
newItems[lookupName] = extensionTypeItem;
384387

385388
encodingContext.withTypeParameters(element.typeParameters, (
@@ -577,6 +580,7 @@ class LibraryManifestBuilder {
577580
element: element,
578581
);
579582
});
583+
mixinItem.hasNonFinalField = element.hasNonFinalField;
580584
newItems[lookupName] = mixinItem;
581585

582586
encodingContext.withTypeParameters(element.typeParameters, (

pkg/analyzer/lib/src/fine/manifest_item.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ClassItem extends InterfaceItem<ClassElementImpl> {
3737
required super.declaredMethods,
3838
required super.declaredConstructors,
3939
required super.inheritedConstructors,
40+
required super.hasNonFinalField,
4041
required super.supertype,
4142
required super.mixins,
4243
required super.interfaces,
@@ -69,6 +70,7 @@ class ClassItem extends InterfaceItem<ClassElementImpl> {
6970
declaredMethods: {},
7071
declaredConstructors: {},
7172
inheritedConstructors: {},
73+
hasNonFinalField: element.hasNonFinalField,
7274
supertype: element.supertype?.encode(context),
7375
mixins: element.mixins.encode(context),
7476
interfaces: element.interfaces.encode(context),
@@ -98,6 +100,7 @@ class ClassItem extends InterfaceItem<ClassElementImpl> {
98100
declaredMethods: InstanceItemMethodItem.readMap(reader),
99101
declaredConstructors: InterfaceItemConstructorItem.readMap(reader),
100102
inheritedConstructors: reader.readLookupNameToIdMap(),
103+
hasNonFinalField: reader.readBool(),
101104
supertype: ManifestType.readOptional(reader),
102105
mixins: ManifestType.readList(reader),
103106
interfaces: ManifestType.readList(reader),
@@ -151,6 +154,7 @@ class EnumItem extends InterfaceItem<EnumElementImpl> {
151154
required super.declaredMethods,
152155
required super.declaredConstructors,
153156
required super.inheritedConstructors,
157+
required super.hasNonFinalField,
154158
required super.interface,
155159
required super.supertype,
156160
required super.mixins,
@@ -176,6 +180,7 @@ class EnumItem extends InterfaceItem<EnumElementImpl> {
176180
declaredMethods: {},
177181
declaredConstructors: {},
178182
inheritedConstructors: {},
183+
hasNonFinalField: element.hasNonFinalField,
179184
interface: ManifestInterface.empty(),
180185
supertype: element.supertype?.encode(context),
181186
mixins: element.mixins.encode(context),
@@ -198,6 +203,7 @@ class EnumItem extends InterfaceItem<EnumElementImpl> {
198203
declaredMethods: InstanceItemMethodItem.readMap(reader),
199204
declaredConstructors: InterfaceItemConstructorItem.readMap(reader),
200205
inheritedConstructors: reader.readLookupNameToIdMap(),
206+
hasNonFinalField: reader.readBool(),
201207
supertype: ManifestType.readOptional(reader),
202208
mixins: ManifestType.readList(reader),
203209
interfaces: ManifestType.readList(reader),
@@ -300,6 +306,7 @@ class ExtensionTypeItem extends InterfaceItem<ExtensionTypeElementImpl> {
300306
required super.declaredMethods,
301307
required super.declaredConstructors,
302308
required super.inheritedConstructors,
309+
required super.hasNonFinalField,
303310
required super.interface,
304311
required super.supertype,
305312
required super.mixins,
@@ -329,6 +336,7 @@ class ExtensionTypeItem extends InterfaceItem<ExtensionTypeElementImpl> {
329336
declaredMethods: {},
330337
declaredConstructors: {},
331338
inheritedConstructors: {},
339+
hasNonFinalField: element.hasNonFinalField,
332340
interface: ManifestInterface.empty(),
333341
supertype: element.supertype?.encode(context),
334342
mixins: element.mixins.encode(context),
@@ -355,6 +363,7 @@ class ExtensionTypeItem extends InterfaceItem<ExtensionTypeElementImpl> {
355363
declaredMethods: InstanceItemMethodItem.readMap(reader),
356364
declaredConstructors: InterfaceItemConstructorItem.readMap(reader),
357365
inheritedConstructors: reader.readLookupNameToIdMap(),
366+
hasNonFinalField: reader.readBool(),
358367
supertype: ManifestType.readOptional(reader),
359368
mixins: ManifestType.readList(reader),
360369
interfaces: ManifestType.readList(reader),
@@ -951,6 +960,7 @@ class InstanceItemSetterItem extends InstanceItemMemberItem<SetterElementImpl> {
951960
/// The item for [InterfaceElementImpl].
952961
sealed class InterfaceItem<E extends InterfaceElementImpl>
953962
extends InstanceItem<E> {
963+
bool hasNonFinalField;
954964
final ManifestType? supertype;
955965
final List<ManifestType> interfaces;
956966
final List<ManifestType> mixins;
@@ -969,6 +979,7 @@ sealed class InterfaceItem<E extends InterfaceElementImpl>
969979
required super.declaredMethods,
970980
required super.declaredConstructors,
971981
required super.inheritedConstructors,
982+
required this.hasNonFinalField,
972983
required this.supertype,
973984
required this.mixins,
974985
required this.interfaces,
@@ -979,6 +990,8 @@ sealed class InterfaceItem<E extends InterfaceElementImpl>
979990
return interface.map[name];
980991
}
981992

993+
/// Intentionally omits [hasNonFinalField], which is tracked as a separate
994+
/// requirement.
982995
@override
983996
bool match(MatchContext context, E element) {
984997
return super.match(context, element) &&
@@ -990,6 +1003,7 @@ sealed class InterfaceItem<E extends InterfaceElementImpl>
9901003
@override
9911004
void write(BufferedSink sink) {
9921005
super.write(sink);
1006+
sink.writeBool(hasNonFinalField);
9931007
supertype.writeOptional(sink);
9941008
mixins.writeList(sink);
9951009
interfaces.writeList(sink);
@@ -1286,6 +1300,7 @@ class MixinItem extends InterfaceItem<MixinElementImpl> {
12861300
required super.declaredSetters,
12871301
required super.declaredConstructors,
12881302
required super.inheritedConstructors,
1303+
required super.hasNonFinalField,
12891304
required super.interface,
12901305
required this.isBase,
12911306
required this.superclassConstraints,
@@ -1313,6 +1328,7 @@ class MixinItem extends InterfaceItem<MixinElementImpl> {
13131328
declaredMethods: {},
13141329
declaredConstructors: {},
13151330
inheritedConstructors: {},
1331+
hasNonFinalField: element.hasNonFinalField,
13161332
interface: ManifestInterface.empty(),
13171333
supertype: element.supertype?.encode(context),
13181334
mixins: element.mixins.encode(context),
@@ -1340,6 +1356,7 @@ class MixinItem extends InterfaceItem<MixinElementImpl> {
13401356
declaredMethods: InstanceItemMethodItem.readMap(reader),
13411357
declaredConstructors: InterfaceItemConstructorItem.readMap(reader),
13421358
inheritedConstructors: reader.readLookupNameToIdMap(),
1359+
hasNonFinalField: reader.readBool(),
13431360
supertype: ManifestType.readOptional(reader),
13441361
mixins: ManifestType.readList(reader),
13451362
interfaces: ManifestType.readList(reader),

pkg/analyzer/lib/src/fine/requirement_failure.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,28 @@ class InterfaceConstructorIdMismatch extends RequirementFailure {
206206
}
207207
}
208208

209+
class InterfaceHasNonFinalFieldMismatch extends RequirementFailure {
210+
final Uri libraryUri;
211+
final LookupName interfaceName;
212+
final bool expected;
213+
final bool actual;
214+
215+
InterfaceHasNonFinalFieldMismatch({
216+
required this.libraryUri,
217+
required this.interfaceName,
218+
required this.expected,
219+
required this.actual,
220+
});
221+
222+
@override
223+
String toString() {
224+
return 'InterfaceHasNonFinalFieldMismatch(libraryUri: $libraryUri, '
225+
'interfaceName: ${interfaceName.asString}, '
226+
'expected: $expected, '
227+
'actual: $actual)';
228+
}
229+
}
230+
209231
class InterfaceIdMismatch extends RequirementFailure {
210232
final Uri libraryUri;
211233
final LookupName interfaceName;

pkg/analyzer/lib/src/fine/requirements.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ class InterfaceItemRequirements {
263263
/// If the element was asked for its full interface.
264264
ManifestItemId? interfaceId;
265265

266+
/// The value of `hasNonFinalField`, if it was requested.
267+
bool? hasNonFinalField;
268+
266269
/// Set if [InstanceElementImpl.constructors] is invoked.
267270
ManifestItemIdList? allConstructors;
268271

@@ -274,6 +277,7 @@ class InterfaceItemRequirements {
274277

275278
InterfaceItemRequirements({
276279
required this.interfaceId,
280+
required this.hasNonFinalField,
277281
required this.allConstructors,
278282
required this.requestedConstructors,
279283
required this.methods,
@@ -282,6 +286,7 @@ class InterfaceItemRequirements {
282286
factory InterfaceItemRequirements.empty() {
283287
return InterfaceItemRequirements(
284288
interfaceId: null,
289+
hasNonFinalField: null,
285290
allConstructors: null,
286291
requestedConstructors: {},
287292
methods: {},
@@ -291,6 +296,7 @@ class InterfaceItemRequirements {
291296
factory InterfaceItemRequirements.read(SummaryDataReader reader) {
292297
return InterfaceItemRequirements(
293298
interfaceId: ManifestItemId.readOptional(reader),
299+
hasNonFinalField: reader.readOptionalBool(),
294300
allConstructors: ManifestItemIdList.readOptional(reader),
295301
requestedConstructors: reader.readNameToOptionalIdMap(),
296302
methods: reader.readNameToOptionalIdMap(),
@@ -299,6 +305,7 @@ class InterfaceItemRequirements {
299305

300306
void write(BufferedSink sink) {
301307
interfaceId.writeOptional(sink);
308+
sink.writeOptionalBool(hasNonFinalField);
302309
allConstructors.writeOptional(sink);
303310
sink.writeNameToIdMap(requestedConstructors);
304311
sink.writeNameToIdMap(methods);
@@ -724,6 +731,18 @@ class RequirementsManifest {
724731
}
725732
}
726733

734+
if (interfaceRequirements.hasNonFinalField case var expected?) {
735+
var actual = interfaceItem.hasNonFinalField;
736+
if (expected != actual) {
737+
return InterfaceHasNonFinalFieldMismatch(
738+
libraryUri: libraryUri,
739+
interfaceName: interfaceName,
740+
expected: expected,
741+
actual: actual,
742+
);
743+
}
744+
}
745+
727746
if (interfaceRequirements.allConstructors case var required?) {
728747
var actualItems = interfaceItem.declaredConstructors.values;
729748
var actualIds = actualItems.map((item) => item.id);
@@ -1065,6 +1084,20 @@ class RequirementsManifest {
10651084
requirements.requestedConstructors[constructorName] = constructorId;
10661085
}
10671086

1087+
void record_interfaceElement_hasNonFinalField({
1088+
required InterfaceElementImpl element,
1089+
}) {
1090+
var itemRequirements = _getInterfaceItem(element);
1091+
if (itemRequirements == null) {
1092+
return;
1093+
}
1094+
1095+
var item = itemRequirements.item;
1096+
var requirements = itemRequirements.requirements;
1097+
1098+
requirements.hasNonFinalField = item.hasNonFinalField;
1099+
}
1100+
10681101
/// Record that all accessible extensions inside a [LibraryFragmentImpl]
10691102
/// are requested, which means dependency on all extensions exported
10701103
/// from [importedLibraries].
@@ -1389,6 +1422,15 @@ extension _BufferedSinkExtension on BufferedSink {
13891422
writeValue: (id) => id.writeOptional(this),
13901423
);
13911424
}
1425+
1426+
void writeOptionalBool(bool? value) {
1427+
if (value == null) {
1428+
writeBool(false);
1429+
} else {
1430+
writeBool(true);
1431+
writeBool(value);
1432+
}
1433+
}
13921434
}
13931435

13941436
extension _SummaryDataReaderExtension on SummaryDataReader {
@@ -1398,4 +1440,12 @@ extension _SummaryDataReaderExtension on SummaryDataReader {
13981440
readValue: () => ManifestItemId.readOptional(this),
13991441
);
14001442
}
1443+
1444+
bool? readOptionalBool() {
1445+
if (readBool()) {
1446+
return readBool();
1447+
} else {
1448+
return null;
1449+
}
1450+
}
14011451
}

0 commit comments

Comments
 (0)