Augment. Update 'augmented' members while building elements.
Found out while working on enum constants merging that we need to
have correct InterfaceScope during ReferenceResolver, before
TypesBuilder.
Change-Id: I5b495e2cd143192329b5bf37c86405c16de7d56c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/363487
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/summary2/augmentation.dart b/pkg/analyzer/lib/src/summary2/augmentation.dart
new file mode 100644
index 0000000..36b773f
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary2/augmentation.dart
@@ -0,0 +1,311 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/utilities/extensions/element.dart';
+
+class AugmentedClassDeclarationBuilder
+ extends AugmentedInstanceDeclarationBuilder {
+ final ClassElementImpl declaration;
+
+ AugmentedClassDeclarationBuilder({
+ required this.declaration,
+ }) {
+ addFields(declaration.fields);
+ addConstructors(declaration.constructors);
+ addAccessors(declaration.accessors);
+ addMethods(declaration.methods);
+ }
+
+ void augment(ClassElementImpl element) {
+ addFields(element.fields);
+ addConstructors(element.constructors);
+ addAccessors(element.accessors);
+ addMethods(element.methods);
+ _updatedAugmented(element);
+ }
+}
+
+class AugmentedEnumDeclarationBuilder
+ extends AugmentedInstanceDeclarationBuilder {
+ final EnumElementImpl declaration;
+
+ AugmentedEnumDeclarationBuilder({
+ required this.declaration,
+ }) {
+ addFields(declaration.fields);
+ addConstructors(declaration.constructors);
+ addAccessors(declaration.accessors);
+ addMethods(declaration.methods);
+ }
+
+ void augment(EnumElementImpl element) {
+ addFields(element.fields);
+ addConstructors(element.constructors);
+ addAccessors(element.accessors);
+ addMethods(element.methods);
+ _updatedAugmented(element);
+ }
+}
+
+class AugmentedExtensionDeclarationBuilder
+ extends AugmentedInstanceDeclarationBuilder {
+ final ExtensionElementImpl declaration;
+
+ AugmentedExtensionDeclarationBuilder({
+ required this.declaration,
+ }) {
+ addFields(declaration.fields);
+ addAccessors(declaration.accessors);
+ addMethods(declaration.methods);
+ }
+
+ void augment(ExtensionElementImpl element) {
+ addFields(element.fields);
+ addAccessors(element.accessors);
+ addMethods(element.methods);
+ _updatedAugmented(element);
+ }
+}
+
+abstract class AugmentedInstanceDeclarationBuilder {
+ final Map<String, FieldElementImpl> fields = {};
+ final Map<String, ConstructorElementImpl> constructors = {};
+ final Map<String, PropertyAccessorElementImpl> accessors = {};
+ final Map<String, MethodElementImpl> methods = {};
+
+ void addAccessors(List<PropertyAccessorElementImpl> elements) {
+ for (var element in elements) {
+ var name = element.name;
+ if (element.isAugmentation) {
+ var existing = accessors[name];
+ if (existing != null) {
+ existing.augmentation = element;
+ element.augmentationTarget = existing;
+ element.variable2 = existing.variable2;
+ }
+ }
+ accessors[name] = element;
+ }
+ }
+
+ void addConstructors(List<ConstructorElementImpl> elements) {
+ for (var element in elements) {
+ var name = element.name;
+ if (element.isAugmentation) {
+ var existing = constructors[name];
+ if (existing != null) {
+ existing.augmentation = element;
+ element.augmentationTarget = existing;
+ }
+ }
+ constructors[name] = element;
+ }
+ }
+
+ void addFields(List<FieldElementImpl> elements) {
+ for (var element in elements) {
+ var name = element.name;
+ if (element.isAugmentation) {
+ var existing = fields[name];
+ if (existing != null) {
+ existing.augmentation = element;
+ element.augmentationTarget = existing;
+ }
+ }
+ fields[name] = element;
+ }
+ }
+
+ void addMethods(List<MethodElementImpl> elements) {
+ for (var element in elements) {
+ var name = element.name;
+ if (element.isAugmentation) {
+ var existing = methods[name];
+ if (existing != null) {
+ existing.augmentation = element;
+ element.augmentationTarget = existing;
+ }
+ }
+ methods[name] = element;
+ }
+ }
+
+ AugmentedInstanceElementImpl? _ensureAugmented(
+ InstanceElementImpl augmentation,
+ ) {
+ var maybeAugmented = augmentation.augmented;
+ if (maybeAugmented is AugmentedInstanceElementImpl) {
+ return maybeAugmented;
+ }
+
+ maybeAugmented as NotAugmentedInstanceElementImpl;
+ var declaration = maybeAugmented.declaration;
+ var augmented = maybeAugmented.toAugmented();
+
+ augmented.fields.addAll(declaration.fields.notAugmented);
+ augmented.accessors.addAll(declaration.accessors.notAugmented);
+ augmented.methods.addAll(declaration.methods.notAugmented);
+
+ if (augmented is AugmentedInterfaceElementImpl) {
+ if (declaration is InterfaceElementImpl) {
+ augmented.mixins.addAll(declaration.mixins);
+ augmented.interfaces.addAll(declaration.interfaces);
+ augmented.constructors.addAll(declaration.constructors.notAugmented);
+ }
+ }
+
+ if (augmented is AugmentedMixinElementImpl) {
+ if (declaration is MixinElementImpl) {
+ augmented.superclassConstraints.addAll(
+ declaration.superclassConstraints,
+ );
+ }
+ }
+
+ return augmented;
+ }
+
+ void _updatedAugmented(InstanceElementImpl augmentation) {
+ assert(augmentation.augmentationTarget != null);
+ var augmented = _ensureAugmented(augmentation);
+ if (augmented == null) {
+ return;
+ }
+
+ var declaration = augmented.declaration;
+ var declarationTypeParameters = declaration.typeParameters;
+
+ var augmentationTypeParameters = augmentation.typeParameters;
+ if (augmentationTypeParameters.length != declarationTypeParameters.length) {
+ return;
+ }
+
+ var toDeclaration = Substitution.fromPairs(
+ augmentationTypeParameters,
+ declarationTypeParameters.instantiateNone(),
+ );
+
+ if (augmentation is InterfaceElementImpl &&
+ declaration is InterfaceElementImpl &&
+ augmented is AugmentedInterfaceElementImpl) {
+ augmented.constructors = [
+ ...augmented.constructors.notAugmented,
+ ...augmentation.constructors.notAugmented.map((element) {
+ if (toDeclaration.map.isEmpty) {
+ return element;
+ }
+ return ConstructorMember(
+ declaration: element,
+ augmentationSubstitution: toDeclaration,
+ substitution: Substitution.empty,
+ );
+ }),
+ ];
+ }
+
+ augmented.fields = [
+ ...augmented.fields.notAugmented,
+ ...augmentation.fields.notAugmented.map((element) {
+ if (toDeclaration.map.isEmpty) {
+ return element;
+ }
+ return FieldMember(element, toDeclaration, Substitution.empty);
+ }),
+ ];
+
+ augmented.accessors = [
+ ...augmented.accessors.notAugmented,
+ ...augmentation.accessors.notAugmented.map((element) {
+ if (toDeclaration.map.isEmpty) {
+ return element;
+ }
+ return PropertyAccessorMember(
+ element, toDeclaration, Substitution.empty);
+ }),
+ ];
+
+ augmented.methods = [
+ ...augmented.methods.notAugmented,
+ ...augmentation.methods.notAugmented.map((element) {
+ if (toDeclaration.map.isEmpty) {
+ return element;
+ }
+ return MethodMember(element, toDeclaration, Substitution.empty);
+ }),
+ ];
+ }
+}
+
+class AugmentedMixinDeclarationBuilder
+ extends AugmentedInstanceDeclarationBuilder {
+ final MixinElementImpl declaration;
+
+ AugmentedMixinDeclarationBuilder({
+ required this.declaration,
+ }) {
+ addFields(declaration.fields);
+ addAccessors(declaration.accessors);
+ addMethods(declaration.methods);
+ }
+
+ void augment(MixinElementImpl element) {
+ addFields(element.fields);
+ addAccessors(element.accessors);
+ addMethods(element.methods);
+ _updatedAugmented(element);
+ }
+}
+
+class AugmentedTopVariablesBuilder {
+ final Map<String, TopLevelVariableElementImpl> variables = {};
+ final Map<String, PropertyAccessorElementImpl> accessors = {};
+
+ void addAccessor(PropertyAccessorElementImpl element) {
+ var name = element.name;
+ if (element.isAugmentation) {
+ var existing = accessors[name];
+ if (existing != null) {
+ existing.augmentation = element;
+ element.augmentationTarget = existing;
+ element.variable2 = existing.variable2;
+ }
+ }
+ accessors[name] = element;
+ }
+
+ void addVariable(TopLevelVariableElementImpl element) {
+ var name = element.name;
+ if (element.isAugmentation) {
+ var existing = variables[name];
+ if (existing != null) {
+ existing.augmentation = element;
+ element.augmentationTarget = existing;
+ }
+ }
+ variables[name] = element;
+
+ if (element.getter case var getter?) {
+ addAccessor(getter);
+ }
+ if (element.setter case var setter?) {
+ addAccessor(setter);
+ }
+ }
+}
+
+extension<T extends ExecutableElement> on List<T> {
+ Iterable<T> get notAugmented {
+ return where((e) => e.augmentation == null);
+ }
+}
+
+extension<T extends PropertyInducingElement> on List<T> {
+ Iterable<T> get notAugmented {
+ return where((e) => e.augmentation == null);
+ }
+}
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index ebc81db..f52e00b 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary2/ast_binary_tokens.dart';
+import 'package:analyzer/src/summary2/augmentation.dart';
import 'package:analyzer/src/summary2/library_builder.dart';
import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/reference.dart';
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 407df46..2b1f4ee 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -18,6 +18,7 @@
as element_model;
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/summary2/augmentation.dart';
import 'package:analyzer/src/summary2/combinator.dart';
import 'package:analyzer/src/summary2/constructor_initializer_resolver.dart';
import 'package:analyzer/src/summary2/default_value_resolver.dart';
@@ -37,187 +38,6 @@
import 'package:analyzer/src/utilities/extensions/object.dart';
import 'package:macros/src/executor.dart' as macro;
-class AugmentedClassDeclarationBuilder
- extends AugmentedInstanceDeclarationBuilder {
- final ClassElementImpl declaration;
-
- AugmentedClassDeclarationBuilder({
- required this.declaration,
- }) {
- addFields(declaration.fields);
- addConstructors(declaration.constructors);
- addAccessors(declaration.accessors);
- addMethods(declaration.methods);
- }
-
- void augment(ClassElementImpl element) {
- addFields(element.fields);
- addConstructors(element.constructors);
- addAccessors(element.accessors);
- addMethods(element.methods);
- }
-}
-
-class AugmentedEnumDeclarationBuilder
- extends AugmentedInstanceDeclarationBuilder {
- final EnumElementImpl declaration;
-
- AugmentedEnumDeclarationBuilder({
- required this.declaration,
- }) {
- addFields(declaration.fields);
- addConstructors(declaration.constructors);
- addAccessors(declaration.accessors);
- addMethods(declaration.methods);
- }
-
- void augment(EnumElementImpl element) {
- addFields(element.fields);
- addConstructors(element.constructors);
- addAccessors(element.accessors);
- addMethods(element.methods);
- }
-}
-
-class AugmentedExtensionDeclarationBuilder
- extends AugmentedInstanceDeclarationBuilder {
- final ExtensionElementImpl declaration;
-
- AugmentedExtensionDeclarationBuilder({
- required this.declaration,
- }) {
- addFields(declaration.fields);
- addAccessors(declaration.accessors);
- addMethods(declaration.methods);
- }
-
- void augment(ExtensionElementImpl element) {
- addFields(element.fields);
- addAccessors(element.accessors);
- addMethods(element.methods);
- }
-}
-
-abstract class AugmentedInstanceDeclarationBuilder {
- final Map<String, FieldElementImpl> fields = {};
- final Map<String, ConstructorElementImpl> constructors = {};
- final Map<String, PropertyAccessorElementImpl> accessors = {};
- final Map<String, MethodElementImpl> methods = {};
-
- void addAccessors(List<PropertyAccessorElementImpl> elements) {
- for (var element in elements) {
- var name = element.name;
- if (element.isAugmentation) {
- var existing = accessors[name];
- if (existing != null) {
- existing.augmentation = element;
- element.augmentationTarget = existing;
- element.variable2 = existing.variable2;
- }
- }
- accessors[name] = element;
- }
- }
-
- void addConstructors(List<ConstructorElementImpl> elements) {
- for (var element in elements) {
- var name = element.name;
- if (element.isAugmentation) {
- var existing = constructors[name];
- if (existing != null) {
- existing.augmentation = element;
- element.augmentationTarget = existing;
- }
- }
- constructors[name] = element;
- }
- }
-
- void addFields(List<FieldElementImpl> elements) {
- for (var element in elements) {
- var name = element.name;
- if (element.isAugmentation) {
- var existing = fields[name];
- if (existing != null) {
- existing.augmentation = element;
- element.augmentationTarget = existing;
- }
- }
- fields[name] = element;
- }
- }
-
- void addMethods(List<MethodElementImpl> elements) {
- for (var element in elements) {
- var name = element.name;
- if (element.isAugmentation) {
- var existing = methods[name];
- if (existing != null) {
- existing.augmentation = element;
- element.augmentationTarget = existing;
- }
- }
- methods[name] = element;
- }
- }
-}
-
-class AugmentedMixinDeclarationBuilder
- extends AugmentedInstanceDeclarationBuilder {
- final MixinElementImpl declaration;
-
- AugmentedMixinDeclarationBuilder({
- required this.declaration,
- }) {
- addFields(declaration.fields);
- addAccessors(declaration.accessors);
- addMethods(declaration.methods);
- }
-
- void augment(MixinElementImpl element) {
- addFields(element.fields);
- addAccessors(element.accessors);
- addMethods(element.methods);
- }
-}
-
-class AugmentedTopVariablesBuilder {
- final Map<String, TopLevelVariableElementImpl> variables = {};
- final Map<String, PropertyAccessorElementImpl> accessors = {};
-
- void addAccessor(PropertyAccessorElementImpl element) {
- var name = element.name;
- if (element.isAugmentation) {
- var existing = accessors[name];
- if (existing != null) {
- existing.augmentation = element;
- element.augmentationTarget = existing;
- element.variable2 = existing.variable2;
- }
- }
- accessors[name] = element;
- }
-
- void addVariable(TopLevelVariableElementImpl element) {
- var name = element.name;
- if (element.isAugmentation) {
- var existing = variables[name];
- if (existing != null) {
- existing.augmentation = element;
- element.augmentationTarget = existing;
- }
- }
- variables[name] = element;
-
- if (element.getter case var getter?) {
- addAccessor(getter);
- }
- if (element.setter case var setter?) {
- addAccessor(setter);
- }
- }
-}
-
class DefiningLinkingUnit extends LinkingUnit {
DefiningLinkingUnit({
required super.reference,
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 549711c..fdcdfc4 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/class_hierarchy.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
@@ -142,11 +141,7 @@
node.implementsClause?.interfaces,
);
- if (element.augmentationTarget != null) {
- _updatedAugmented(element, withClause: node.withClause);
- } else {
- _toInferMixins[element] = _ToInferMixins(element, node.withClause);
- }
+ _updatedAugmented(element, withClause: node.withClause);
}
void _classTypeAlias(ClassTypeAlias node) {
@@ -230,41 +225,6 @@
}
}
- AugmentedInstanceElementImpl? _ensureAugmented(
- InstanceElementImpl augmentation,
- ) {
- var maybeAugmented = augmentation.augmented;
- if (maybeAugmented is AugmentedInstanceElementImpl) {
- return maybeAugmented;
- }
-
- maybeAugmented as NotAugmentedInstanceElementImpl;
- var declaration = maybeAugmented.declaration;
- var augmented = maybeAugmented.toAugmented();
-
- augmented.fields.addAll(declaration.fields.notAugmented);
- augmented.accessors.addAll(declaration.accessors.notAugmented);
- augmented.methods.addAll(declaration.methods.notAugmented);
-
- if (augmented is AugmentedInterfaceElementImpl) {
- if (declaration is InterfaceElementImpl) {
- augmented.mixins.addAll(declaration.mixins);
- augmented.interfaces.addAll(declaration.interfaces);
- augmented.constructors.addAll(declaration.constructors.notAugmented);
- }
- }
-
- if (augmented is AugmentedMixinElementImpl) {
- if (declaration is MixinElementImpl) {
- augmented.superclassConstraints.addAll(
- declaration.superclassConstraints,
- );
- }
- }
-
- return augmented;
- }
-
void _enumDeclaration(EnumDeclaration node) {
var element = node.declaredElement as EnumElementImpl;
@@ -272,11 +232,7 @@
node.implementsClause?.interfaces,
);
- if (element.augmentationTarget != null) {
- _updatedAugmented(element, withClause: node.withClause);
- } else {
- _toInferMixins[element] = _ToInferMixins(element, node.withClause);
- }
+ _updatedAugmented(element, withClause: node.withClause);
}
void _extensionDeclaration(ExtensionDeclaration node) {
@@ -359,9 +315,7 @@
node.implementsClause?.interfaces,
);
- if (element.augmentationTarget != null) {
- _updatedAugmented(element);
- }
+ _updatedAugmented(element);
}
NullabilitySuffix _nullability(AstNode node, bool hasQuestion) {
@@ -399,19 +353,27 @@
}
void _updatedAugmented(
- InstanceElementImpl augmentation, {
+ InstanceElementImpl element, {
WithClause? withClause,
}) {
- assert(augmentation.augmentationTarget != null);
- var augmented = _ensureAugmented(augmentation);
- if (augmented == null) {
+ // Always schedule mixin inference for the declaration.
+ if (element.augmentationTarget == null) {
+ if (element is InterfaceElementImpl) {
+ _toInferMixins[element] = _ToInferMixins(element, withClause);
+ }
+ }
+
+ // Here we merge declaration and augmentations.
+ // If there are no augmentations, nothing to do.
+ var augmented = element.augmented;
+ if (augmented is! AugmentedInstanceElementImpl) {
return;
}
var declaration = augmented.declaration;
var declarationTypeParameters = declaration.typeParameters;
- var augmentationTypeParameters = augmentation.typeParameters;
+ var augmentationTypeParameters = element.typeParameters;
if (augmentationTypeParameters.length != declarationTypeParameters.length) {
return;
}
@@ -426,25 +388,28 @@
augmentationTypeParameters.instantiateNone(),
);
- if (augmentation is InterfaceElementImpl && withClause != null) {
- var toInferMixins = _toInferMixins[declaration];
- if (toInferMixins != null) {
- toInferMixins.augmentations.add(
- _ToInferMixinsAugmentation(
- element: augmentation,
- withClause: withClause,
- toDeclaration: toDeclaration,
- fromDeclaration: fromDeclaration,
- ),
- );
+ // Schedule mixing inference for augmentations.
+ if (element.augmentationTarget != null) {
+ if (element is InterfaceElementImpl && withClause != null) {
+ var toInferMixins = _toInferMixins[declaration];
+ if (toInferMixins != null) {
+ toInferMixins.augmentations.add(
+ _ToInferMixinsAugmentation(
+ element: element,
+ withClause: withClause,
+ toDeclaration: toDeclaration,
+ fromDeclaration: fromDeclaration,
+ ),
+ );
+ }
}
}
- if (augmentation is InterfaceElementImpl &&
+ if (element is InterfaceElementImpl &&
declaration is InterfaceElementImpl &&
augmented is AugmentedInterfaceElementImpl) {
if (declaration.supertype == null) {
- var elementSuperType = augmentation.supertype;
+ var elementSuperType = element.supertype;
if (elementSuperType != null) {
var superType = toDeclaration.mapInterfaceType(elementSuperType);
declaration.supertype = superType;
@@ -452,61 +417,15 @@
}
augmented.interfaces.addAll(
- toDeclaration.mapInterfaceTypes(augmentation.interfaces),
+ toDeclaration.mapInterfaceTypes(element.interfaces),
);
-
- augmented.constructors = [
- ...augmented.constructors.notAugmented,
- ...augmentation.constructors.notAugmented.map((element) {
- if (toDeclaration.map.isEmpty) {
- return element;
- }
- return ConstructorMember(
- declaration: element,
- augmentationSubstitution: toDeclaration,
- substitution: Substitution.empty,
- );
- }),
- ];
}
- if (augmentation is MixinElementImpl &&
- augmented is AugmentedMixinElementImpl) {
+ if (element is MixinElementImpl && augmented is AugmentedMixinElementImpl) {
augmented.superclassConstraints.addAll(
- toDeclaration.mapInterfaceTypes(augmentation.superclassConstraints),
+ toDeclaration.mapInterfaceTypes(element.superclassConstraints),
);
}
-
- augmented.fields = [
- ...augmented.fields.notAugmented,
- ...augmentation.fields.notAugmented.map((element) {
- if (toDeclaration.map.isEmpty) {
- return element;
- }
- return FieldMember(element, toDeclaration, Substitution.empty);
- }),
- ];
-
- augmented.accessors = [
- ...augmented.accessors.notAugmented,
- ...augmentation.accessors.notAugmented.map((element) {
- if (toDeclaration.map.isEmpty) {
- return element;
- }
- return PropertyAccessorMember(
- element, toDeclaration, Substitution.empty);
- }),
- ];
-
- augmented.methods = [
- ...augmented.methods.notAugmented,
- ...augmentation.methods.notAugmented.map((element) {
- if (toDeclaration.map.isEmpty) {
- return element;
- }
- return MethodMember(element, toDeclaration, Substitution.empty);
- }),
- ];
}
/// The [FunctionType] to use when a function type is expected for a type
@@ -796,15 +715,3 @@
assert(element.isAugmentation);
}
}
-
-extension<T extends ExecutableElement> on List<T> {
- Iterable<T> get notAugmented {
- return where((e) => e.augmentation == null);
- }
-}
-
-extension<T extends PropertyInducingElement> on List<T> {
- Iterable<T> get notAugmented {
- return where((e) => e.augmentation == null);
- }
-}