[kernel] Add ExtensionTypeDeclaration.procedures

This adds a list of `Procedure`s to `ExtensionTypeDeclaration`. This is
meant to model representation fields and combined member signatures
computed from inherited non-extension type members.

These are not meant to be handled by the backends. The combined
member signature can be the interface target of an `InstanceInvocation`
expression but will always have a `.memberSignatureOrigin` value from
one of the original class members.

TEST=existing

Change-Id: I87768ed75a3c7126b0a30f8ccf06e46678c56db6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330301
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2023-10-13 07:42:29 +00:00 committed by Commit Queue
parent 06ab207091
commit f87142fdc2
27 changed files with 260 additions and 166 deletions

View file

@ -254,7 +254,7 @@ extension ExtensionMemberDescriptorExtension on ExtensionMemberDescriptor {
bool get isSetter => kind == ExtensionMemberKind.Setter;
bool get isMethod => kind == ExtensionMemberKind.Method;
bool get isExternal => (member.asProcedure).isExternal;
bool get isExternal => (memberReference.asProcedure).isExternal;
}
extension ProcedureExtension on Procedure {

View file

@ -714,8 +714,8 @@ class ExtensionIndex {
void _indexExtensions(Library library) {
if (_processedExtensionLibraries.contains(library)) return;
for (var extension in library.extensions) {
for (var descriptor in extension.members) {
var reference = descriptor.member;
for (var descriptor in extension.memberDescriptors) {
var reference = descriptor.memberReference;
var onType = extension.onType;
bool isInteropOnType = false;
Annotatable? cls;
@ -738,7 +738,7 @@ class ExtensionIndex {
_extensionMemberIndex[reference] = descriptor;
_extensionAnnotatableIndex[reference] = cls!;
_extensionIndex[reference] = extension;
final tearOffReference = descriptor.tearOff;
final tearOffReference = descriptor.tearOffReference;
if (tearOffReference != null) {
_extensionMemberIndex[tearOffReference] = descriptor;
_extensionIndex[tearOffReference] = extension;
@ -832,11 +832,11 @@ class ExtensionIndex {
if (_processedExtensionTypeLibraries.contains(library)) return;
for (var extensionType in library.extensionTypeDeclarations) {
if (isInteropExtensionType(extensionType)) {
for (var descriptor in extensionType.members) {
final reference = descriptor.member;
for (var descriptor in extensionType.memberDescriptors) {
final reference = descriptor.memberReference;
_extensionTypeMemberIndex[reference] = descriptor;
_extensionTypeIndex[reference] = extensionType;
final tearOffReference = descriptor.tearOff;
final tearOffReference = descriptor.tearOffReference;
if (tearOffReference != null) {
_extensionTypeMemberIndex[tearOffReference] = descriptor;
_extensionTypeIndex[tearOffReference] = extensionType;

View file

@ -199,7 +199,7 @@ class StaticInteropMockValidator {
// setters return their return and parameter types, respectively.
DartType _getTypeOfDescriptor(ExtensionMemberDescriptor interopDescriptor) {
// CFE creates static procedures for each extension member.
var interopMember = interopDescriptor.member.asProcedure;
var interopMember = interopDescriptor.memberReference.asProcedure;
if (interopDescriptor.isGetter) {
return interopMember.function.returnType;
@ -325,7 +325,7 @@ class StaticInteropMockValidator {
var extensions = _staticInteropClassesWithExtensions[cls.reference];
if (extensions != null) {
for (var extension in extensions) {
for (var descriptor in extension.members) {
for (var descriptor in extension.memberDescriptors) {
if (!descriptor.isExternal || descriptor.isStatic) continue;
// No need to handle external fields - they are transformed to
// external getters/setters by the CFE.
@ -336,7 +336,8 @@ class StaticInteropMockValidator {
}
_descriptorToExtensionName[descriptor] =
extension.isUnnamedExtension ? '<unnamed>' : extension.name;
var name = js_interop.getJSName(descriptor.member.asMember);
var name =
js_interop.getJSName(descriptor.memberReference.asMember);
if (name.isEmpty) name = descriptor.name.text;
exportNameToDescriptors!
.putIfAbsent(name, () => {})

View file

@ -77,9 +77,10 @@ String? computeKernelElementNameForSourceMaps(
String _findExtensionMemberName(ir.Member member) {
assert(member.isExtensionMember);
for (ir.Extension extension in member.enclosingLibrary.extensions) {
for (ir.ExtensionMemberDescriptor descriptor in extension.members) {
if (descriptor.member == member.reference ||
descriptor.tearOff == member.reference) {
for (ir.ExtensionMemberDescriptor descriptor
in extension.memberDescriptors) {
if (descriptor.memberReference == member.reference ||
descriptor.tearOffReference == member.reference) {
String extensionName;
// Anonymous extensions contain a # on their synthetic name.
if (extension.name.contains('#')) {

View file

@ -32,20 +32,20 @@ class DillExtensionBuilder extends ExtensionBuilderImpl {
parent: parent.scope,
debugName: "extension ${extension.name}",
isModifiable: false)) {
for (ExtensionMemberDescriptor descriptor in extension.members) {
for (ExtensionMemberDescriptor descriptor in extension.memberDescriptors) {
Name name = descriptor.name;
switch (descriptor.kind) {
case ExtensionMemberKind.Method:
if (descriptor.isStatic) {
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(
name.text,
new DillExtensionStaticMethodBuilder(
procedure, descriptor, this),
setter: false);
} else {
Procedure procedure = descriptor.member.asProcedure;
Procedure? tearOff = descriptor.tearOff?.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
Procedure? tearOff = descriptor.tearOffReference?.asProcedure;
assert(tearOff != null, "No tear found for ${descriptor}");
scope.addLocalMember(
name.text,
@ -55,25 +55,25 @@ class DillExtensionBuilder extends ExtensionBuilderImpl {
}
break;
case ExtensionMemberKind.Getter:
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(name.text,
new DillExtensionGetterBuilder(procedure, descriptor, this),
setter: false);
break;
case ExtensionMemberKind.Field:
Field field = descriptor.member.asField;
Field field = descriptor.memberReference.asField;
scope.addLocalMember(
name.text, new DillExtensionFieldBuilder(field, descriptor, this),
setter: false);
break;
case ExtensionMemberKind.Setter:
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(name.text,
new DillExtensionSetterBuilder(procedure, descriptor, this),
setter: true);
break;
case ExtensionMemberKind.Operator:
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(name.text,
new DillExtensionOperatorBuilder(procedure, descriptor, this),
setter: false);

View file

@ -43,20 +43,20 @@ class DillExtensionTypeDeclarationBuilder
new ConstructorScope(
_extensionTypeDeclaration.name, <String, MemberBuilder>{})) {
for (ExtensionTypeMemberDescriptor descriptor
in _extensionTypeDeclaration.members) {
in _extensionTypeDeclaration.memberDescriptors) {
Name name = descriptor.name;
switch (descriptor.kind) {
case ExtensionTypeMemberKind.Method:
if (descriptor.isStatic) {
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(
name.text,
new DillExtensionTypeStaticMethodBuilder(
procedure, descriptor, this),
setter: false);
} else {
Procedure procedure = descriptor.member.asProcedure;
Procedure? tearOff = descriptor.tearOff?.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
Procedure? tearOff = descriptor.tearOffReference?.asProcedure;
assert(tearOff != null, "No tear found for ${descriptor}");
scope.addLocalMember(
name.text,
@ -66,32 +66,32 @@ class DillExtensionTypeDeclarationBuilder
}
break;
case ExtensionTypeMemberKind.Getter:
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(name.text,
new DillExtensionTypeGetterBuilder(procedure, descriptor, this),
setter: false);
break;
case ExtensionTypeMemberKind.Field:
Field field = descriptor.member.asField;
Field field = descriptor.memberReference.asField;
scope.addLocalMember(name.text,
new DillExtensionTypeFieldBuilder(field, descriptor, this),
setter: false);
break;
case ExtensionTypeMemberKind.Setter:
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(name.text,
new DillExtensionTypeSetterBuilder(procedure, descriptor, this),
setter: true);
break;
case ExtensionTypeMemberKind.Operator:
Procedure procedure = descriptor.member.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
scope.addLocalMember(name.text,
new DillExtensionTypeOperatorBuilder(procedure, descriptor, this),
setter: false);
break;
case ExtensionTypeMemberKind.Constructor:
Procedure procedure = descriptor.member.asProcedure;
Procedure? tearOff = descriptor.tearOff?.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
Procedure? tearOff = descriptor.tearOffReference?.asProcedure;
constructorScope.addLocalMember(
name.text,
new DillExtensionTypeConstructorBuilder(
@ -99,8 +99,8 @@ class DillExtensionTypeDeclarationBuilder
break;
case ExtensionTypeMemberKind.Factory:
case ExtensionTypeMemberKind.RedirectingFactory:
Procedure procedure = descriptor.member.asProcedure;
Procedure? tearOff = descriptor.tearOff?.asProcedure;
Procedure procedure = descriptor.memberReference.asProcedure;
Procedure? tearOff = descriptor.tearOffReference?.asProcedure;
constructorScope.addLocalMember(
name.text,
new DillExtensionTypeFactoryBuilder(

View file

@ -149,10 +149,10 @@ class SourceExtensionBuilder extends ExtensionBuilderImpl
kind = ExtensionMemberKind.Operator;
break;
}
extension.members.add(new ExtensionMemberDescriptor(
extension.memberDescriptors.add(new ExtensionMemberDescriptor(
name: new Name(name, libraryBuilder.library),
member: memberReference,
tearOff: tearOffReference,
memberReference: memberReference,
tearOffReference: tearOffReference,
isStatic: memberBuilder.isStatic,
kind: kind));
}

View file

@ -503,12 +503,13 @@ class SourceExtensionTypeDeclarationBuilder
kind = ExtensionTypeMemberKind.Operator;
break;
}
extensionTypeDeclaration.members.add(new ExtensionTypeMemberDescriptor(
name: new Name(name, libraryBuilder.library),
member: memberReference,
tearOff: tearOffReference,
isStatic: memberBuilder.isStatic,
kind: kind));
extensionTypeDeclaration.memberDescriptors.add(
new ExtensionTypeMemberDescriptor(
name: new Name(name, libraryBuilder.library),
memberReference: memberReference,
tearOffReference: tearOffReference,
isStatic: memberBuilder.isStatic,
kind: kind));
}
@override

View file

@ -986,33 +986,33 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
Member? targetTearoff;
ProcedureKind? targetKind;
for (ExtensionTypeMemberDescriptor descriptor
in extensionType.extensionTypeDeclaration.members) {
in extensionType.extensionTypeDeclaration.memberDescriptors) {
if (descriptor.name == name) {
switch (descriptor.kind) {
case ExtensionTypeMemberKind.Method:
if (!isSetter) {
targetMember = descriptor.member.asMember;
targetTearoff = descriptor.tearOff?.asMember;
targetMember = descriptor.memberReference.asMember;
targetTearoff = descriptor.tearOffReference?.asMember;
targetKind = ProcedureKind.Method;
}
break;
case ExtensionTypeMemberKind.Getter:
if (!isSetter) {
targetMember = descriptor.member.asMember;
targetMember = descriptor.memberReference.asMember;
targetTearoff = null;
targetKind = ProcedureKind.Getter;
}
break;
case ExtensionTypeMemberKind.Setter:
if (isSetter) {
targetMember = descriptor.member.asMember;
targetMember = descriptor.memberReference.asMember;
targetTearoff = null;
targetKind = ProcedureKind.Setter;
}
break;
case ExtensionTypeMemberKind.Operator:
if (!isSetter) {
targetMember = descriptor.member.asMember;
targetMember = descriptor.memberReference.asMember;
targetTearoff = null;
targetKind = ProcedureKind.Operator;
}

View file

@ -853,9 +853,9 @@ List<String> extensionMethodDescriptorToText(
}
return [
descriptorToText(descriptor.member, forTearOff: false),
if (descriptor.tearOff != null)
descriptorToText(descriptor.tearOff!, forTearOff: true),
descriptorToText(descriptor.memberReference, forTearOff: false),
if (descriptor.tearOffReference != null)
descriptorToText(descriptor.tearOffReference!, forTearOff: true),
];
}

View file

@ -217,7 +217,7 @@ class ExtensionsDataExtractor extends CfeDataExtractor<Features> {
features.addElement(
Tags.extensionTypeParameters, typeParameterToText(typeParameter));
}
for (ExtensionMemberDescriptor descriptor in extension.members) {
for (ExtensionMemberDescriptor descriptor in extension.memberDescriptors) {
for (String text in extensionMethodDescriptorToText(descriptor)) {
features.addElement(Tags.extensionMembers, text);
}

View file

@ -400,6 +400,7 @@ dereferencing
deregister
descent
descriptive
descriptors
deserializable
deserializer
deserializers

View file

@ -117,6 +117,7 @@ const Map<String?, Map<String, FieldRule?>> _fieldRuleMap = {
},
'ExtensionTypeDeclaration': {
'typeParameters': FieldRule(isDeclaration: true),
'_procedures': FieldRule(name: 'procedures'),
},
'Field': {
'reference': FieldRule(name: 'fieldReference'),

View file

@ -147,7 +147,7 @@ type CanonicalName {
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 111;
UInt32 formatVersion = 112;
Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
@ -374,6 +374,7 @@ type ExtensionTypeDeclaration extends Node {
DartType declaredRepresentationType;
StringReference representationName;
List<DartType> implements;
List<Procedure> procedures;
List<ExtensionTypeMemberKind> members;
}

View file

@ -1570,7 +1570,7 @@ class Extension extends NamedNode
///
/// The members are converted into top-level members and only accessible
/// by reference through [ExtensionMemberDescriptor].
List<ExtensionMemberDescriptor> members;
List<ExtensionMemberDescriptor> memberDescriptors;
@override
List<Expression> annotations = const <Expression>[];
@ -1594,11 +1594,12 @@ class Extension extends NamedNode
{required this.name,
List<TypeParameter>? typeParameters,
DartType? onType,
List<ExtensionMemberDescriptor>? members,
List<ExtensionMemberDescriptor>? memberDescriptors,
required this.fileUri,
Reference? reference})
: this.typeParameters = typeParameters ?? <TypeParameter>[],
this.members = members ?? <ExtensionMemberDescriptor>[],
this.memberDescriptors =
memberDescriptors ?? <ExtensionMemberDescriptor>[],
super(reference) {
setParents(this.typeParameters, this);
if (onType != null) {
@ -1722,18 +1723,18 @@ class ExtensionMemberDescriptor {
int flags = 0;
/// Reference to the top-level member created for the extension method.
final Reference member;
final Reference memberReference;
/// Reference to the top-level member created for the extension member tear
/// off, if any.
final Reference? tearOff;
final Reference? tearOffReference;
ExtensionMemberDescriptor(
{required this.name,
required this.kind,
bool isStatic = false,
required this.member,
required this.tearOff}) {
required this.memberReference,
required this.tearOffReference}) {
this.isStatic = isStatic;
}
@ -1747,7 +1748,7 @@ class ExtensionMemberDescriptor {
@override
String toString() {
return 'ExtensionMemberDescriptor($name,$kind,'
'${member.toStringInternal()},isStatic=${isStatic})';
'${memberReference.toStringInternal()},isStatic=${isStatic})';
}
}
@ -1790,11 +1791,19 @@ class ExtensionTypeDeclaration extends NamedNode
/// library of the extension type declaration.
late String representationName;
/// Abstract procedures that are part of the extension type declaration
/// interface.
///
/// This includes a getter for the representation field and member signatures
/// computed as the combined member signature of inherited non-extension type
/// members.
List<Procedure> _procedures;
/// The members declared by the extension type declaration.
///
/// The members are converted into top-level members and only accessible
/// by reference through [ExtensionTypeMemberDescriptor].
List<ExtensionTypeMemberDescriptor> members;
List<ExtensionTypeMemberDescriptor> memberDescriptors;
@override
List<Expression> annotations = const <Expression>[];
@ -1816,15 +1825,19 @@ class ExtensionTypeDeclaration extends NamedNode
{required this.name,
List<TypeParameter>? typeParameters,
DartType? declaredRepresentationType,
List<ExtensionTypeMemberDescriptor>? members,
List<ExtensionTypeMemberDescriptor>? memberDescriptors,
List<DartType>? implements,
List<Procedure>? procedures,
required this.fileUri,
Reference? reference})
: this.typeParameters = typeParameters ?? <TypeParameter>[],
this.members = members ?? <ExtensionTypeMemberDescriptor>[],
this.memberDescriptors =
memberDescriptors ?? <ExtensionTypeMemberDescriptor>[],
this.implements = implements ?? <DartType>[],
this._procedures = procedures ?? <Procedure>[],
super(reference) {
setParents(this.typeParameters, this);
setParents(this._procedures, this);
if (declaredRepresentationType != null) {
this.declaredRepresentationType = declaredRepresentationType;
}
@ -1837,6 +1850,20 @@ class ExtensionTypeDeclaration extends NamedNode
Library get enclosingLibrary => parent as Library;
void addProcedure(Procedure procedure) {
procedure.parent = this;
procedures.add(procedure);
}
List<Procedure> get procedures => _procedures;
/// Internal. Should *ONLY* be used from within kernel.
///
/// Used for adding procedures when reading the dill file.
void set proceduresInternal(List<Procedure> procedures) {
_procedures = procedures;
}
@override
R accept<R>(TreeVisitor<R> v) => v.visitExtensionTypeDeclaration(this);
@ -1852,6 +1879,7 @@ class ExtensionTypeDeclaration extends NamedNode
visitList(annotations, v);
visitList(typeParameters, v);
declaredRepresentationType.accept(v);
visitList(procedures, v);
}
@override
@ -1859,6 +1887,7 @@ class ExtensionTypeDeclaration extends NamedNode
v.transformList(annotations, this);
v.transformList(typeParameters, this);
declaredRepresentationType = v.visitDartType(declaredRepresentationType);
v.transformList(procedures, this);
}
@override
@ -1867,6 +1896,7 @@ class ExtensionTypeDeclaration extends NamedNode
v.transformTypeParameterList(typeParameters, this);
declaredRepresentationType =
v.visitDartType(declaredRepresentationType, cannotRemoveSentinel);
v.transformProcedureList(procedures, this);
}
@override
@ -1933,18 +1963,18 @@ class ExtensionTypeMemberDescriptor {
/// Reference to the top-level member created for the extension type
/// declaration member.
final Reference member;
final Reference memberReference;
/// Reference to the top-level member created for the extension type
/// declaration member tear off, if any.
final Reference? tearOff;
final Reference? tearOffReference;
ExtensionTypeMemberDescriptor(
{required this.name,
required this.kind,
bool isStatic = false,
required this.member,
required this.tearOff}) {
required this.memberReference,
required this.tearOffReference}) {
this.isStatic = isStatic;
}
@ -1959,8 +1989,8 @@ class ExtensionTypeMemberDescriptor {
@override
String toString() {
return 'ExtensionTypeMemberDescriptor($name,$kind,'
'${member.toStringInternal()},isStatic=${isStatic},'
'${tearOff?.toStringInternal()})';
'${memberReference.toStringInternal()},isStatic=${isStatic},'
'${tearOffReference?.toStringInternal()})';
}
}
@ -15296,8 +15326,8 @@ final ExtensionMemberDescriptor dummyExtensionMemberDescriptor =
new ExtensionMemberDescriptor(
name: dummyName,
kind: ExtensionMemberKind.Getter,
member: dummyReference,
tearOff: null);
memberReference: dummyReference,
tearOffReference: null);
/// Non-nullable [ExtensionTypeDeclaration] dummy value.
///
@ -15316,8 +15346,8 @@ final ExtensionTypeMemberDescriptor dummyExtensionTypeMemberDescriptor =
new ExtensionTypeMemberDescriptor(
name: dummyName,
kind: ExtensionTypeMemberKind.Getter,
member: dummyReference,
tearOff: null);
memberReference: dummyReference,
tearOffReference: null);
/// Non-nullable [ExtensionType] dummy value.
///

View file

@ -1361,6 +1361,19 @@ class BinaryBuilder {
return list;
}
List<Procedure> _readProcedureListWithoutOffsets(TreeNode parent) {
int length = readUInt30();
if (!useGrowableLists && length == 0) {
// When lists don't have to be growable anyway, we might as well use an
// almost constant one for the empty list.
return emptyListOfProcedure;
}
List<Procedure> list = new List<Procedure>.generate(length, (int index) {
return readProcedure(/* no end offset = */ -1)..parent = parent;
}, growable: useGrowableLists);
return list;
}
void _readLibraryDependencies(Library library) {
int length = readUInt30();
if (!useGrowableLists && length == 0) {
@ -1571,7 +1584,7 @@ class BinaryBuilder {
node.fileUri = fileUri;
node.onType = onType;
node.members = _readExtensionMemberDescriptorList();
node.memberDescriptors = _readExtensionMemberDescriptorList();
return node;
}
@ -1597,8 +1610,8 @@ class BinaryBuilder {
return new ExtensionMemberDescriptor(
name: name,
kind: ExtensionMemberKind.values[kind],
member: memberName.reference,
tearOff: tearOffName?.reference)
memberReference: memberName.reference,
tearOffReference: tearOffName?.reference)
..flags = flags;
}
@ -1639,6 +1652,8 @@ class BinaryBuilder {
DartType representationType = readDartType();
String representationName = readStringReference();
List<DartType> implements = _readExtensionTypeDeclarationImplementsList();
node.proceduresInternal = _readProcedureListWithoutOffsets(node);
typeParameterStack.length = 0;
node.name = name;
@ -1647,7 +1662,8 @@ class BinaryBuilder {
node.representationName = representationName;
node.implements = implements;
node.members = _readExtensionTypeMemberDescriptorList();
node.memberDescriptors = _readExtensionTypeMemberDescriptorList();
return node;
}
@ -1684,8 +1700,8 @@ class BinaryBuilder {
return new ExtensionTypeMemberDescriptor(
name: name,
kind: ExtensionTypeMemberKind.values[kind],
member: memberName.reference,
tearOff: tearOffName?.reference)
memberReference: memberName.reference,
tearOffReference: tearOffName?.reference)
..flags = flags;
}

View file

@ -2646,17 +2646,17 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
leaveScope(typeParameters: node.typeParameters);
final int len = node.members.length;
final int len = node.memberDescriptors.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
final ExtensionMemberDescriptor descriptor = node.members[i];
final ExtensionMemberDescriptor descriptor = node.memberDescriptors[i];
writeName(descriptor.name);
writeByte(descriptor.kind.index);
writeByte(descriptor.flags);
assert(descriptor.member.canonicalName != null,
assert(descriptor.memberReference.canonicalName != null,
"No canonical name for ${descriptor}.");
writeNonNullCanonicalNameReference(descriptor.member);
writeNullAllowedCanonicalNameReference(descriptor.tearOff);
writeNonNullCanonicalNameReference(descriptor.memberReference);
writeNullAllowedCanonicalNameReference(descriptor.tearOffReference);
}
}
@ -2679,23 +2679,25 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
writeDartType(node.declaredRepresentationType);
writeStringReference(node.representationName);
writeNodeList(node.implements);
writeProcedureNodeList(node.procedures);
leaveScope(typeParameters: node.typeParameters);
final int len = node.members.length;
final int len = node.memberDescriptors.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
final ExtensionTypeMemberDescriptor descriptor = node.members[i];
final ExtensionTypeMemberDescriptor descriptor =
node.memberDescriptors[i];
writeName(descriptor.name);
writeByte(descriptor.kind.index);
writeByte(descriptor.flags);
assert(descriptor.member.canonicalName != null,
assert(descriptor.memberReference.canonicalName != null,
"No canonical name for ${descriptor}.");
writeNonNullCanonicalNameReference(descriptor.member);
writeNonNullCanonicalNameReference(descriptor.memberReference);
assert(
descriptor.tearOff == null ||
descriptor.tearOff?.canonicalName != null,
descriptor.tearOffReference == null ||
descriptor.tearOffReference?.canonicalName != null,
"No canonical name for ${descriptor} tear-off.");
writeNullAllowedCanonicalNameReference(descriptor.tearOff);
writeNullAllowedCanonicalNameReference(descriptor.tearOffReference);
}
}

View file

@ -226,7 +226,7 @@ class Tag {
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 111;
static const int BinaryFormatVersion = 112;
}
abstract class ConstantTag {

View file

@ -247,7 +247,7 @@ class _MemberTable {
class_!.fields.forEach(_addMember);
class_!.constructors.forEach(_addMember);
} else if (extension_ != null) {
extension_!.members.forEach(_addExtensionMember);
extension_!.memberDescriptors.forEach(_addExtensionMember);
} else {
library.procedures.forEach(_addMember);
library.fields.forEach(_addMember);
@ -307,8 +307,8 @@ class _MemberTable {
_members![name] = replacement;
}
addReference(extensionMember.member, forTearOff: false);
addReference(extensionMember.tearOff, forTearOff: true);
addReference(extensionMember.memberReference, forTearOff: false);
addReference(extensionMember.tearOffReference, forTearOff: true);
}
String get containerName {

View file

@ -129,8 +129,9 @@ class IndexedLibrary extends IndexedContainer {
// repurposing these canonical names.
for (Extension extension in unnamedExtensions) {
extension.reference.canonicalName?.unbind();
for (ExtensionMemberDescriptor descriptor in extension.members) {
Reference reference = descriptor.member;
for (ExtensionMemberDescriptor descriptor
in extension.memberDescriptors) {
Reference reference = descriptor.memberReference;
Member member = reference.asMember;
if (member is Field) {
member.fieldReference.canonicalName?.unbind();
@ -139,7 +140,7 @@ class IndexedLibrary extends IndexedContainer {
} else {
member.reference.canonicalName?.unbind();
}
descriptor.tearOff?.canonicalName?.unbind();
descriptor.tearOffReference?.canonicalName?.unbind();
}
}
}

View file

@ -1715,10 +1715,11 @@ class EquivalenceStrategy {
if (!checkExtensionMemberDescriptor_flags(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionMemberDescriptor_member(visitor, node, other)) {
if (!checkExtensionMemberDescriptor_memberReference(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionMemberDescriptor_tearOff(visitor, node, other)) {
if (!checkExtensionMemberDescriptor_tearOffReference(
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
return result;
@ -1746,7 +1747,7 @@ class EquivalenceStrategy {
if (!checkExtension_onType(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtension_members(visitor, node, other)) {
if (!checkExtension_memberDescriptors(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtension_annotations(visitor, node, other)) {
@ -1780,10 +1781,12 @@ class EquivalenceStrategy {
if (!checkExtensionTypeMemberDescriptor_flags(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionTypeMemberDescriptor_member(visitor, node, other)) {
if (!checkExtensionTypeMemberDescriptor_memberReference(
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionTypeMemberDescriptor_tearOff(visitor, node, other)) {
if (!checkExtensionTypeMemberDescriptor_tearOffReference(
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
return result;
@ -1816,7 +1819,11 @@ class EquivalenceStrategy {
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionTypeDeclaration_members(visitor, node, other)) {
if (!checkExtensionTypeDeclaration_procedures(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionTypeDeclaration_memberDescriptors(
visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkExtensionTypeDeclaration_annotations(visitor, node, other)) {
@ -6022,24 +6029,31 @@ class EquivalenceStrategy {
return visitor.checkValues(node.flags, other.flags, 'flags');
}
bool checkExtensionMemberDescriptor_member(EquivalenceVisitor visitor,
ExtensionMemberDescriptor node, ExtensionMemberDescriptor other) {
return visitor.checkReferences(node.member, other.member, 'member');
bool checkExtensionMemberDescriptor_memberReference(
EquivalenceVisitor visitor,
ExtensionMemberDescriptor node,
ExtensionMemberDescriptor other) {
return visitor.checkReferences(
node.memberReference, other.memberReference, 'memberReference');
}
bool checkExtensionMemberDescriptor_tearOff(EquivalenceVisitor visitor,
ExtensionMemberDescriptor node, ExtensionMemberDescriptor other) {
return visitor.checkReferences(node.tearOff, other.tearOff, 'tearOff');
bool checkExtensionMemberDescriptor_tearOffReference(
EquivalenceVisitor visitor,
ExtensionMemberDescriptor node,
ExtensionMemberDescriptor other) {
return visitor.checkReferences(
node.tearOffReference, other.tearOffReference, 'tearOffReference');
}
bool checkExtension_members(
bool checkExtension_memberDescriptors(
EquivalenceVisitor visitor, Extension node, Extension other) {
return visitor.checkLists(node.members, other.members, (a, b, _) {
return visitor.checkLists(node.memberDescriptors, other.memberDescriptors,
(a, b, _) {
if (identical(a, b)) return true;
if (a is! ExtensionMemberDescriptor) return false;
if (b is! ExtensionMemberDescriptor) return false;
return checkExtensionMemberDescriptor(visitor, a, b);
}, 'members');
}, 'memberDescriptors');
}
bool checkExtension_annotations(
@ -6095,6 +6109,12 @@ class EquivalenceStrategy {
other.representationName, 'representationName');
}
bool checkExtensionTypeDeclaration_procedures(EquivalenceVisitor visitor,
ExtensionTypeDeclaration node, ExtensionTypeDeclaration other) {
return visitor.checkLists(
node.procedures, other.procedures, visitor.checkNodes, 'procedures');
}
bool checkExtensionTypeMemberDescriptor_name(EquivalenceVisitor visitor,
ExtensionTypeMemberDescriptor node, ExtensionTypeMemberDescriptor other) {
return visitor.checkNodes(node.name, other.name, 'name');
@ -6110,24 +6130,33 @@ class EquivalenceStrategy {
return visitor.checkValues(node.flags, other.flags, 'flags');
}
bool checkExtensionTypeMemberDescriptor_member(EquivalenceVisitor visitor,
ExtensionTypeMemberDescriptor node, ExtensionTypeMemberDescriptor other) {
return visitor.checkReferences(node.member, other.member, 'member');
bool checkExtensionTypeMemberDescriptor_memberReference(
EquivalenceVisitor visitor,
ExtensionTypeMemberDescriptor node,
ExtensionTypeMemberDescriptor other) {
return visitor.checkReferences(
node.memberReference, other.memberReference, 'memberReference');
}
bool checkExtensionTypeMemberDescriptor_tearOff(EquivalenceVisitor visitor,
ExtensionTypeMemberDescriptor node, ExtensionTypeMemberDescriptor other) {
return visitor.checkReferences(node.tearOff, other.tearOff, 'tearOff');
bool checkExtensionTypeMemberDescriptor_tearOffReference(
EquivalenceVisitor visitor,
ExtensionTypeMemberDescriptor node,
ExtensionTypeMemberDescriptor other) {
return visitor.checkReferences(
node.tearOffReference, other.tearOffReference, 'tearOffReference');
}
bool checkExtensionTypeDeclaration_members(EquivalenceVisitor visitor,
ExtensionTypeDeclaration node, ExtensionTypeDeclaration other) {
return visitor.checkLists(node.members, other.members, (a, b, _) {
bool checkExtensionTypeDeclaration_memberDescriptors(
EquivalenceVisitor visitor,
ExtensionTypeDeclaration node,
ExtensionTypeDeclaration other) {
return visitor.checkLists(node.memberDescriptors, other.memberDescriptors,
(a, b, _) {
if (identical(a, b)) return true;
if (a is! ExtensionTypeMemberDescriptor) return false;
if (b is! ExtensionTypeMemberDescriptor) return false;
return checkExtensionTypeMemberDescriptor(visitor, a, b);
}, 'members');
}, 'memberDescriptors');
}
bool checkExtensionTypeDeclaration_annotations(EquivalenceVisitor visitor,

View file

@ -1360,7 +1360,7 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
endLine(endLineString);
++indentation;
node.members.forEach((ExtensionMemberDescriptor descriptor) {
node.memberDescriptors.forEach((ExtensionMemberDescriptor descriptor) {
void writeReference(Reference reference, {required bool isTearOff}) {
writeIndentation();
writeModifier(descriptor.isStatic, 'static');
@ -1398,9 +1398,9 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
endLine(';');
}
writeReference(descriptor.member, isTearOff: false);
if (descriptor.tearOff != null) {
writeReference(descriptor.tearOff!, isTearOff: true);
writeReference(descriptor.memberReference, isTearOff: false);
if (descriptor.tearOffReference != null) {
writeReference(descriptor.tearOffReference!, isTearOff: true);
}
});
--indentation;
@ -1430,7 +1430,8 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
endLine(endLineString);
++indentation;
node.members.forEach((ExtensionTypeMemberDescriptor descriptor) {
node.procedures.forEach(writeNode);
node.memberDescriptors.forEach((ExtensionTypeMemberDescriptor descriptor) {
void writeReference(Reference reference, {required bool isTearOff}) {
writeIndentation();
writeModifier(descriptor.isStatic, 'static');
@ -1477,9 +1478,9 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
endLine(';');
}
writeReference(descriptor.member, isTearOff: false);
if (descriptor.tearOff != null) {
writeReference(descriptor.tearOff!, isTearOff: true);
writeReference(descriptor.memberReference, isTearOff: false);
if (descriptor.tearOffReference != null) {
writeReference(descriptor.tearOffReference!, isTearOff: true);
}
});
--indentation;

View file

@ -710,13 +710,13 @@ class WidgetCreatorTracker {
return;
}
for (ExtensionMemberDescriptor member in extension.members) {
for (ExtensionMemberDescriptor member in extension.memberDescriptors) {
if (member.isStatic) {
// We could support static extension methods but it is not clear that
// there is a use case for this.
continue;
}
final Procedure method = member.member.asProcedure;
final Procedure method = member.memberReference.asProcedure;
if (_hasWidgetFactoryAnnotation(method)) {
_maybeAddNamedParameter(
method.function,
@ -730,7 +730,7 @@ class WidgetCreatorTracker {
),
);
}
final Procedure? tearOff = member.tearOff?.asProcedure;
final Procedure? tearOff = member.tearOffReference?.asProcedure;
if (tearOff != null && _hasWidgetFactoryAnnotation(tearOff)) {
_maybeAddNamedParameter(
tearOff.function,

View file

@ -403,8 +403,9 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
if (_extensionsMembers == null) {
Map<Reference, ExtensionMemberDescriptor> map = _extensionsMembers = {};
for (Extension extension in library.extensions) {
for (ExtensionMemberDescriptor descriptor in extension.members) {
Reference memberReference = descriptor.member;
for (ExtensionMemberDescriptor descriptor
in extension.memberDescriptors) {
Reference memberReference = descriptor.memberReference;
map[memberReference] = descriptor;
Member member = memberReference.asMember;
if (!member.isExtensionMember) {
@ -413,7 +414,7 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
"Member $member (${descriptor}) from $extension is not marked "
"as an extension member.");
}
Reference? tearOffReference = descriptor.tearOff;
Reference? tearOffReference = descriptor.tearOffReference;
if (tearOffReference != null) {
map[tearOffReference] = descriptor;
Member tearOff = tearOffReference.asMember;
@ -438,8 +439,8 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
for (ExtensionTypeDeclaration extensionTypeDeclaration
in library.extensionTypeDeclarations) {
for (ExtensionTypeMemberDescriptor descriptor
in extensionTypeDeclaration.members) {
Reference memberReference = descriptor.member;
in extensionTypeDeclaration.memberDescriptors) {
Reference memberReference = descriptor.memberReference;
map[memberReference] = descriptor;
Member member = memberReference.asMember;
if (!member.isExtensionTypeMember) {
@ -448,7 +449,7 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
"Member $member (${descriptor}) from $extensionTypeDeclaration "
"is not marked as an extension type member.");
}
Reference? tearOffReference = descriptor.tearOff;
Reference? tearOffReference = descriptor.tearOffReference;
if (tearOffReference != null) {
map[tearOffReference] = descriptor;
Member tearOff = tearOffReference.asMember;

View file

@ -877,9 +877,9 @@ class TreeShaker {
if (m.isExtensionMember) {
// The AST should have exactly one [Extension] for [m].
final extension = m.enclosingLibrary.extensions.firstWhere((extension) {
return extension.members.any((descriptor) =>
descriptor.member.asMember == m ||
descriptor.tearOff?.asMember == m);
return extension.memberDescriptors.any((descriptor) =>
descriptor.memberReference.asMember == m ||
descriptor.tearOffReference?.asMember == m);
});
// Ensure we retain the [Extension] itself (though members might be
@ -894,9 +894,9 @@ class TreeShaker {
final extensionTypeDeclaration = m
.enclosingLibrary.extensionTypeDeclarations
.firstWhere((extensionTypeDeclaration) {
return extensionTypeDeclaration.members.any((descriptor) =>
descriptor.member.asMember == m ||
descriptor.tearOff?.asMember == m);
return extensionTypeDeclaration.memberDescriptors.any((descriptor) =>
descriptor.memberReference.asMember == m ||
descriptor.tearOffReference?.asMember == m);
});
// Ensure we retain the [ExtensionTypeDeclaration] itself (though
@ -1985,17 +1985,17 @@ class _TreeShakerPass2 extends RemovingTransformer {
TreeNode visitExtension(Extension node, TreeNode? removalSentinel) {
if (shaker.isExtensionUsed(node)) {
int writeIndex = 0;
for (int i = 0; i < node.members.length; ++i) {
ExtensionMemberDescriptor descriptor = node.members[i];
for (int i = 0; i < node.memberDescriptors.length; ++i) {
ExtensionMemberDescriptor descriptor = node.memberDescriptors[i];
// To avoid depending on the order in which members and extensions are
// visited during the transformation, we handle both cases: either the
// member was already removed or it will be removed later.
final Reference memberReference = descriptor.member;
final Reference memberReference = descriptor.memberReference;
final bool memberIsBound = memberReference.node != null;
final bool isMemberUsed =
memberIsBound && shaker.isMemberUsed(memberReference.asMember);
final Reference? tearOffReference = descriptor.tearOff;
final Reference? tearOffReference = descriptor.tearOffReference;
final bool tearOffIsBound = tearOffReference?.node != null;
final bool isTearOffUsed =
tearOffIsBound && shaker.isMemberUsed(tearOffReference!.asMember);
@ -2008,16 +2008,16 @@ class _TreeShakerPass2 extends RemovingTransformer {
name: descriptor.name,
kind: descriptor.kind,
isStatic: descriptor.isStatic,
member: descriptor.member,
tearOff: null);
memberReference: descriptor.memberReference,
tearOffReference: null);
}
node.members[writeIndex++] = descriptor;
node.memberDescriptors[writeIndex++] = descriptor;
}
}
node.members.length = writeIndex;
node.memberDescriptors.length = writeIndex;
// We only retain the extension if at least one member is retained.
assert(node.members.isNotEmpty);
assert(node.memberDescriptors.isNotEmpty);
return node;
}
return removalSentinel!;
@ -2028,18 +2028,18 @@ class _TreeShakerPass2 extends RemovingTransformer {
ExtensionTypeDeclaration node, TreeNode? removalSentinel) {
if (shaker.isExtensionTypeDeclarationUsed(node)) {
int writeIndex = 0;
for (int i = 0; i < node.members.length; ++i) {
ExtensionTypeMemberDescriptor descriptor = node.members[i];
for (int i = 0; i < node.memberDescriptors.length; ++i) {
ExtensionTypeMemberDescriptor descriptor = node.memberDescriptors[i];
// To avoid depending on the order in which members and extension type
// declarations are visited during the transformation, we handle both
// cases: either the member was already removed or it will be removed
// later.
final Reference memberReference = descriptor.member;
final Reference memberReference = descriptor.memberReference;
final bool memberIsBound = memberReference.node != null;
final bool isMemberUsed =
memberIsBound && shaker.isMemberUsed(memberReference.asMember);
final Reference? tearOffReference = descriptor.tearOff;
final Reference? tearOffReference = descriptor.tearOffReference;
final bool tearOffIsBound = tearOffReference?.node != null;
final bool isTearOffUsed =
tearOffIsBound && shaker.isMemberUsed(tearOffReference!.asMember);
@ -2052,17 +2052,17 @@ class _TreeShakerPass2 extends RemovingTransformer {
name: descriptor.name,
kind: descriptor.kind,
isStatic: descriptor.isStatic,
member: descriptor.member,
tearOff: null);
memberReference: descriptor.memberReference,
tearOffReference: null);
}
node.members[writeIndex++] = descriptor;
node.memberDescriptors[writeIndex++] = descriptor;
}
}
node.members.length = writeIndex;
node.memberDescriptors.length = writeIndex;
// We only retain the extension type declaration if at least one member is
// retained.
assert(node.members.isNotEmpty);
assert(node.memberDescriptors.isNotEmpty);
return node;
}
return removalSentinel!;

View file

@ -18,7 +18,7 @@ namespace kernel {
// package:kernel/binary.md.
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
static const uint32_t kSupportedKernelFormatVersion = 111;
static const uint32_t kSupportedKernelFormatVersion = 112;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \

View file

@ -1002,6 +1002,14 @@ void KernelLoader::FinishTopLevelClassLoading(
helper_.SkipStringReference(); // skip representation name.
helper_.SkipListOfDartTypes(); // skip implements types.
// Skip extension type procedures.
const intptr_t extension_type_procedure_count =
helper_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < extension_type_procedure_count; ++i) {
ProcedureHelper procedure_helper(&helper_);
procedure_helper.ReadUntilExcluding(ProcedureHelper::kEnd);
}
const intptr_t extension_type_member_count = helper_.ReadListLength();
for (intptr_t j = 0; j < extension_type_member_count; ++j) {
helper_.SkipName(); // skip name.