blob: f4ec2171d68a774b020c56c771151bcaeae47c31 [file] [log] [blame]
// Copyright (c) 2023, 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:front_end/src/fasta/builder/record_type_builder.dart';
import 'package:front_end/src/fasta/kernel/body_builder_context.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/reference_from_index.dart';
import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';
import '../../base/common.dart';
import '../builder/builder.dart';
import '../builder/constructor_reference_builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../builder/metadata_builder.dart';
import '../builder/name_iterator.dart';
import '../builder/type_builder.dart';
import '../kernel/hierarchy/hierarchy_builder.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/type_algorithms.dart';
import '../messages.dart';
import '../problems.dart';
import '../scope.dart';
import '../type_inference/type_inference_engine.dart';
import '../util/helpers.dart';
import 'class_declaration.dart';
import 'source_builder_mixins.dart';
import 'source_constructor_builder.dart';
import 'source_field_builder.dart';
import 'source_library_builder.dart';
import 'source_member_builder.dart';
class SourceExtensionTypeDeclarationBuilder
extends ExtensionTypeDeclarationBuilderImpl
with SourceDeclarationBuilderMixin, ClassDeclarationMixin
implements
Comparable<SourceExtensionTypeDeclarationBuilder>,
ClassDeclaration {
@override
final List<ConstructorReferenceBuilder>? constructorReferences;
final ExtensionTypeDeclaration _extensionTypeDeclaration;
bool _builtRepresentationTypeAndName = false;
SourceExtensionTypeDeclarationBuilder? _origin;
SourceExtensionTypeDeclarationBuilder? patchForTesting;
MergedClassMemberScope? _mergedScope;
@override
final List<NominalVariableBuilder>? typeParameters;
@override
List<TypeBuilder>? interfaceBuilders;
final SourceFieldBuilder? representationFieldBuilder;
final IndexedContainer? indexedContainer;
SourceExtensionTypeDeclarationBuilder(
List<MetadataBuilder>? metadata,
int modifiers,
String name,
this.typeParameters,
this.interfaceBuilders,
Scope scope,
ConstructorScope constructorScope,
SourceLibraryBuilder parent,
this.constructorReferences,
int startOffset,
int nameOffset,
int endOffset,
this.indexedContainer,
this.representationFieldBuilder)
: _extensionTypeDeclaration = new ExtensionTypeDeclaration(
name: name,
fileUri: parent.fileUri,
typeParameters: NominalVariableBuilder.typeParametersFromBuilders(
typeParameters),
reference: indexedContainer?.reference)
..fileOffset = nameOffset,
super(metadata, modifiers, name, parent, nameOffset, scope,
constructorScope);
@override
SourceLibraryBuilder get libraryBuilder =>
super.libraryBuilder as SourceLibraryBuilder;
@override
TypeBuilder? get declaredRepresentationTypeBuilder =>
representationFieldBuilder?.type;
@override
SourceExtensionTypeDeclarationBuilder get origin => _origin ?? this;
// TODO(johnniwinther): Add merged scope for extension type declarations.
MergedClassMemberScope get mergedScope => _mergedScope ??= isPatch
? origin.mergedScope
: throw new UnimplementedError(
"SourceExtensionTypeDeclarationBuilder.mergedScope");
@override
ExtensionTypeDeclaration get extensionTypeDeclaration =>
isPatch ? origin._extensionTypeDeclaration : _extensionTypeDeclaration;
@override
Annotatable get annotatable => extensionTypeDeclaration;
@override
int compareTo(SourceExtensionTypeDeclarationBuilder other) {
int result = "$fileUri".compareTo("${other.fileUri}");
if (result != 0) return result;
return charOffset.compareTo(other.charOffset);
}
/// Builds the [ExtensionTypeDeclaration] for this extension type declaration
/// builder and inserts the members into the [Library] of [libraryBuilder].
///
/// [addMembersToLibrary] is `true` if the extension type members should be
/// added to the library. This is `false` if the extension type declaration is
/// in conflict with another library member. In this case, the extension type
/// member should not be added to the library to avoid name clashes with other
/// members in the library.
ExtensionTypeDeclaration build(LibraryBuilder coreLibrary,
{required bool addMembersToLibrary}) {
if (interfaceBuilders != null) {
for (int i = 0; i < interfaceBuilders!.length; ++i) {
TypeBuilder typeBuilder = interfaceBuilders![i];
TypeAliasBuilder? aliasBuilder =
typeBuilder.declaration is TypeAliasBuilder
? typeBuilder.declaration as TypeAliasBuilder
: null;
DartType interface =
typeBuilder.build(libraryBuilder, TypeUse.superType);
Message? errorMessage;
List<LocatedMessage>? errorContext;
if (typeParameters?.isNotEmpty ?? false) {
for (NominalVariableBuilder variable in typeParameters!) {
int variance = computeTypeVariableBuilderVariance(
variable, typeBuilder, libraryBuilder);
if (!Variance.greaterThanOrEqual(variance, variable.variance)) {
if (variable.parameter.isLegacyCovariant) {
errorMessage =
templateWrongTypeParameterVarianceInSuperinterface
.withArguments(variable.name, interface,
libraryBuilder.isNonNullableByDefault);
} else {
errorMessage =
templateInvalidTypeVariableInSupertypeWithVariance
.withArguments(
Variance.keywordString(variable.variance),
variable.name,
Variance.keywordString(variance),
typeBuilder.typeName!.name);
}
}
}
if (errorMessage != null) {
libraryBuilder.addProblem(errorMessage, typeBuilder.charOffset!,
noLength, typeBuilder.fileUri,
context: errorContext);
errorMessage = null;
}
}
if (interface is ExtensionType) {
if (interface.nullability == Nullability.nullable) {
errorMessage =
templateSuperExtensionTypeIsNullableAliased.withArguments(
typeBuilder.fullNameForErrors,
interface,
libraryBuilder.isNonNullableByDefault);
if (aliasBuilder != null) {
errorContext = [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
];
}
} else {
extensionTypeDeclaration.implements.add(interface);
}
} else if (interface is InterfaceType) {
if (interface.isPotentiallyNullable) {
errorMessage =
templateSuperExtensionTypeIsNullableAliased.withArguments(
typeBuilder.fullNameForErrors,
interface,
libraryBuilder.isNonNullableByDefault);
if (aliasBuilder != null) {
errorContext = [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
];
}
} else {
Class cls = interface.classNode;
if (LibraryBuilder.isObject(cls, coreLibrary) ||
LibraryBuilder.isFunction(cls, coreLibrary) ||
LibraryBuilder.isRecord(cls, coreLibrary)) {
if (aliasBuilder != null) {
errorMessage =
templateSuperExtensionTypeIsIllegalAliased.withArguments(
typeBuilder.fullNameForErrors,
interface,
libraryBuilder.isNonNullableByDefault);
errorContext = [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
];
} else {
errorMessage = templateSuperExtensionTypeIsIllegal
.withArguments(typeBuilder.fullNameForErrors);
}
} else {
extensionTypeDeclaration.implements.add(interface);
}
}
} else if (interface is TypeParameterType) {
errorMessage = templateSuperExtensionTypeIsTypeVariable
.withArguments(typeBuilder.fullNameForErrors);
if (aliasBuilder != null) {
errorContext = [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
];
}
} else {
if (aliasBuilder != null) {
errorMessage =
templateSuperExtensionTypeIsIllegalAliased.withArguments(
typeBuilder.fullNameForErrors,
interface,
libraryBuilder.isNonNullableByDefault);
errorContext = [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
];
} else {
errorMessage = templateSuperExtensionTypeIsIllegal
.withArguments(typeBuilder.fullNameForErrors);
}
}
if (errorMessage != null) {
libraryBuilder.addProblem(errorMessage, typeBuilder.charOffset!,
noLength, typeBuilder.fileUri,
context: errorContext);
}
}
}
buildRepresentationTypeAndName();
buildInternal(coreLibrary, addMembersToLibrary: addMembersToLibrary);
return _extensionTypeDeclaration;
}
@override
void buildRepresentationTypeAndName() {
// We cut the potential infinite recursion here. The cyclic dependencies
// should be reported elsewhere.
if (_builtRepresentationTypeAndName) return;
_builtRepresentationTypeAndName = true;
DartType representationType;
String representationName;
if (representationFieldBuilder != null) {
TypeBuilder typeBuilder = representationFieldBuilder!.type;
if (typeBuilder.isExplicit) {
if (_checkRepresentationDependency(typeBuilder, {this}, {})) {
representationType = const InvalidType();
} else {
representationType =
typeBuilder.build(libraryBuilder, TypeUse.fieldType);
if (typeParameters != null) {
IncludesTypeParametersNonCovariantly checker =
new IncludesTypeParametersNonCovariantly(
extensionTypeDeclaration.typeParameters,
// We are checking the returned type (field/getter type or return
// type of a method) and this is a covariant position.
initialVariance: Variance.covariant);
if (representationType.accept(checker)) {
libraryBuilder.addProblem(
messageNonCovariantTypeParameterInRepresentationType,
typeBuilder.charOffset!,
noLength,
typeBuilder.fileUri);
}
}
if (isBottom(representationType)) {
libraryBuilder.addProblem(
messageExtensionTypeRepresentationTypeBottom,
representationFieldBuilder!.charOffset,
representationFieldBuilder!.name.length,
representationFieldBuilder!.fileUri);
representationType = const InvalidType();
}
}
} else {
representationType = const DynamicType();
}
representationName = representationFieldBuilder!.name;
} else {
representationType = const InvalidType();
representationName = '#';
}
_extensionTypeDeclaration.declaredRepresentationType = representationType;
_extensionTypeDeclaration.representationName = representationName;
}
bool _checkRepresentationDependency(
TypeBuilder? typeBuilder,
Set<ExtensionTypeDeclarationBuilder> seenExtensionTypeDeclarations,
Set<TypeAliasBuilder> usedTypeAliasBuilders) {
TypeBuilder? unaliased = typeBuilder?.unalias(
usedTypeAliasBuilders: usedTypeAliasBuilders,
// We allow creating new type variables during unaliasing. This type
// variables are short-lived and therefore don't need to be bound.
unboundTypeVariables: []);
switch (unaliased) {
case NamedTypeBuilder(
:TypeDeclarationBuilder? declaration,
typeArguments: List<TypeBuilder>? arguments
):
if (declaration is ExtensionTypeDeclarationBuilder) {
if (!seenExtensionTypeDeclarations.add(declaration)) {
List<LocatedMessage> context = [];
for (ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder
in seenExtensionTypeDeclarations) {
if (extensionTypeDeclarationBuilder != this) {
context.add(messageExtensionTypeDeclarationCause.withLocation(
extensionTypeDeclarationBuilder.fileUri,
extensionTypeDeclarationBuilder.charOffset,
extensionTypeDeclarationBuilder.name.length));
}
}
for (TypeAliasBuilder typeAliasBuilder in usedTypeAliasBuilders) {
context.add(messageTypedefCause.withLocation(
typeAliasBuilder.fileUri,
typeAliasBuilder.charOffset,
typeAliasBuilder.name.length));
}
libraryBuilder.addProblem(
messageCyclicRepresentationDependency,
representationFieldBuilder!.type.charOffset!,
noLength,
representationFieldBuilder!.type.fileUri,
context: context);
return true;
} else {
TypeBuilder? representationTypeBuilder =
declaration.declaredRepresentationTypeBuilder;
if (representationTypeBuilder != null) {
if (_checkRepresentationDependency(
representationTypeBuilder,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
}
}
}
if (arguments != null) {
for (TypeBuilder typeArgument in arguments) {
if (_checkRepresentationDependency(
typeArgument,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
}
}
case FunctionTypeBuilder(
:List<StructuralVariableBuilder>? typeVariables,
:List<ParameterBuilder>? formals,
:TypeBuilder returnType
):
if (_checkRepresentationDependency(
returnType,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
if (formals != null) {
for (ParameterBuilder formal in formals) {
if (_checkRepresentationDependency(
formal.type,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
}
}
if (typeVariables != null) {
for (StructuralVariableBuilder typeVariable in typeVariables) {
TypeBuilder? bound = typeVariable.bound;
if (_checkRepresentationDependency(
bound,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
}
}
case RecordTypeBuilder(
:List<RecordTypeFieldBuilder>? positionalFields,
:List<RecordTypeFieldBuilder>? namedFields
):
if (positionalFields != null) {
for (RecordTypeFieldBuilder field in positionalFields) {
if (_checkRepresentationDependency(
field.type,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
}
}
if (namedFields != null) {
for (RecordTypeFieldBuilder field in namedFields) {
if (_checkRepresentationDependency(
field.type,
seenExtensionTypeDeclarations.toSet(),
usedTypeAliasBuilders.toSet())) {
return true;
}
}
}
case OmittedTypeBuilder():
case FixedTypeBuilder():
case InvalidTypeBuilder():
case null:
}
return false;
}
void checkSupertypes(
CoreTypes coreTypes, ClassHierarchyBuilder hierarchyBuilder) {
if (interfaceBuilders != null) {
for (int i = 0; i < interfaceBuilders!.length; ++i) {
TypeBuilder typeBuilder = interfaceBuilders![i];
DartType interface =
typeBuilder.build(libraryBuilder, TypeUse.superType);
if (interface is InterfaceType) {
if (!hierarchyBuilder.types.isSubtypeOf(declaredRepresentationType,
interface, SubtypeCheckMode.withNullabilities)) {
libraryBuilder.addProblem(
templateInvalidExtensionTypeSuperInterface.withArguments(
interface, declaredRepresentationType, name, true),
typeBuilder.charOffset!,
noLength,
typeBuilder.fileUri);
}
} else if (interface is ExtensionType) {
DartType instantiatedRepresentationType =
Substitution.fromExtensionType(interface).substituteType(interface
.extensionTypeDeclaration.declaredRepresentationType);
if (!hierarchyBuilder.types.isSubtypeOf(
declaredRepresentationType,
instantiatedRepresentationType,
SubtypeCheckMode.withNullabilities)) {
libraryBuilder.addProblem(
templateInvalidExtensionTypeSuperExtensionType.withArguments(
declaredRepresentationType,
name,
instantiatedRepresentationType,
interface,
true),
typeBuilder.charOffset!,
noLength,
typeBuilder.fileUri);
}
}
}
}
}
@override
void buildOutlineExpressions(
ClassHierarchy classHierarchy,
List<DelayedActionPerformer> delayedActionPerformers,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
super.buildOutlineExpressions(
classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
Iterator<SourceMemberBuilder> iterator = constructorScope.filteredIterator(
parent: this, includeDuplicates: false, includeAugmentations: true);
while (iterator.moveNext()) {
iterator.current.buildOutlineExpressions(
classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
}
}
@override
void addMemberInternal(SourceMemberBuilder memberBuilder,
BuiltMemberKind memberKind, Member member, Member? tearOff) {
switch (memberKind) {
case BuiltMemberKind.Constructor:
case BuiltMemberKind.RedirectingFactory:
case BuiltMemberKind.Field:
case BuiltMemberKind.Method:
case BuiltMemberKind.Factory:
case BuiltMemberKind.ExtensionMethod:
case BuiltMemberKind.ExtensionGetter:
case BuiltMemberKind.ExtensionSetter:
case BuiltMemberKind.ExtensionOperator:
case BuiltMemberKind.ExtensionField:
case BuiltMemberKind.LateIsSetField:
case BuiltMemberKind.ExtensionTypeConstructor:
case BuiltMemberKind.ExtensionTypeFactory:
case BuiltMemberKind.ExtensionTypeRedirectingFactory:
case BuiltMemberKind.ExtensionTypeMethod:
case BuiltMemberKind.ExtensionTypeGetter:
case BuiltMemberKind.LateGetter:
case BuiltMemberKind.ExtensionTypeSetter:
case BuiltMemberKind.LateSetter:
case BuiltMemberKind.ExtensionTypeOperator:
unhandled(
"${memberBuilder.runtimeType}:${memberKind}",
"addMemberInternal",
memberBuilder.charOffset,
memberBuilder.fileUri);
case BuiltMemberKind.ExtensionTypeRepresentationField:
assert(tearOff == null, "Unexpected tear-off $tearOff");
extensionTypeDeclaration.addProcedure(member as Procedure);
}
}
@override
void addMemberDescriptorInternal(
SourceMemberBuilder memberBuilder,
BuiltMemberKind memberKind,
Reference memberReference,
Reference? tearOffReference) {
String name = memberBuilder.name;
ExtensionTypeMemberKind kind;
switch (memberKind) {
case BuiltMemberKind.Constructor:
case BuiltMemberKind.RedirectingFactory:
case BuiltMemberKind.Field:
case BuiltMemberKind.Method:
case BuiltMemberKind.Factory:
case BuiltMemberKind.ExtensionMethod:
case BuiltMemberKind.ExtensionGetter:
case BuiltMemberKind.ExtensionSetter:
case BuiltMemberKind.ExtensionOperator:
case BuiltMemberKind.ExtensionTypeRepresentationField:
unhandled("${memberBuilder.runtimeType}:${memberKind}", "buildMembers",
memberBuilder.charOffset, memberBuilder.fileUri);
case BuiltMemberKind.ExtensionField:
case BuiltMemberKind.LateIsSetField:
kind = ExtensionTypeMemberKind.Field;
break;
case BuiltMemberKind.ExtensionTypeConstructor:
kind = ExtensionTypeMemberKind.Constructor;
break;
case BuiltMemberKind.ExtensionTypeFactory:
kind = ExtensionTypeMemberKind.Factory;
break;
case BuiltMemberKind.ExtensionTypeRedirectingFactory:
kind = ExtensionTypeMemberKind.RedirectingFactory;
break;
case BuiltMemberKind.ExtensionTypeMethod:
kind = ExtensionTypeMemberKind.Method;
break;
case BuiltMemberKind.ExtensionTypeGetter:
case BuiltMemberKind.LateGetter:
kind = ExtensionTypeMemberKind.Getter;
break;
case BuiltMemberKind.ExtensionTypeSetter:
case BuiltMemberKind.LateSetter:
kind = ExtensionTypeMemberKind.Setter;
break;
case BuiltMemberKind.ExtensionTypeOperator:
kind = ExtensionTypeMemberKind.Operator;
break;
}
extensionTypeDeclaration.memberDescriptors.add(
new ExtensionTypeMemberDescriptor(
name: new Name(name, libraryBuilder.library),
memberReference: memberReference,
tearOffReference: tearOffReference,
isStatic: memberBuilder.isStatic,
kind: kind));
}
@override
void applyPatch(Builder patch) {
if (patch is SourceExtensionTypeDeclarationBuilder) {
patch._origin = this;
if (retainDataForTesting) {
patchForTesting = patch;
}
scope.forEachLocalMember((String name, Builder member) {
Builder? memberPatch =
patch.scope.lookupLocalMember(name, setter: false);
if (memberPatch != null) {
member.applyPatch(memberPatch);
}
});
scope.forEachLocalSetter((String name, Builder member) {
Builder? memberPatch =
patch.scope.lookupLocalMember(name, setter: true);
if (memberPatch != null) {
member.applyPatch(memberPatch);
}
});
// TODO(johnniwinther): Check that type parameters and on-type match
// with origin declaration.
} else {
libraryBuilder.addProblem(messagePatchDeclarationMismatch,
patch.charOffset, noLength, patch.fileUri, context: [
messagePatchDeclarationOrigin.withLocation(
fileUri, charOffset, noLength)
]);
}
}
/// Looks up the constructor by [name] on the class built by this class
/// builder.
SourceExtensionTypeConstructorBuilder? lookupConstructor(Name name) {
if (name.text == "new") {
name = new Name("", name.library);
}
Builder? builder = constructorScope.lookupLocalMember(name.text);
if (builder is SourceExtensionTypeConstructorBuilder) {
return builder;
}
return null;
}
@override
DartType get declaredRepresentationType =>
_extensionTypeDeclaration.declaredRepresentationType;
@override
Iterator<T> fullMemberIterator<T extends Builder>() =>
new ClassDeclarationMemberIterator<SourceExtensionTypeDeclarationBuilder,
T>(
const _SourceExtensionTypeDeclarationBuilderAugmentationAccess(),
this,
includeDuplicates: false);
@override
NameIterator<T> fullMemberNameIterator<T extends Builder>() =>
new ClassDeclarationMemberNameIterator<
SourceExtensionTypeDeclarationBuilder, T>(
const _SourceExtensionTypeDeclarationBuilderAugmentationAccess(),
this,
includeDuplicates: false);
@override
Iterator<T> fullConstructorIterator<T extends MemberBuilder>() =>
new ClassDeclarationConstructorIterator<
SourceExtensionTypeDeclarationBuilder, T>(
const _SourceExtensionTypeDeclarationBuilderAugmentationAccess(),
this,
includeDuplicates: false);
@override
NameIterator<T> fullConstructorNameIterator<T extends MemberBuilder>() =>
new ClassDeclarationConstructorNameIterator<
SourceExtensionTypeDeclarationBuilder, T>(
const _SourceExtensionTypeDeclarationBuilderAugmentationAccess(),
this,
includeDuplicates: false);
@override
bool get isMixinDeclaration => false;
@override
bool get hasGenerativeConstructor {
// TODO(johnniwinther): Support default constructor? and factories.
return true;
}
@override
BodyBuilderContext get bodyBuilderContext =>
new ExtensionTypeBodyBuilderContext(this);
/// Return a map whose keys are the supertypes of this
/// [SourceExtensionTypeDeclarationBuilder] after expansion of type aliases,
/// if any. For each supertype key, the corresponding value is the type alias
/// which was unaliased in order to find the supertype, or null if the
/// supertype was not aliased.
Map<TypeDeclarationBuilder?, TypeAliasBuilder?> computeDirectSupertypes() {
final Map<TypeDeclarationBuilder?, TypeAliasBuilder?> result = {};
final List<TypeBuilder>? interfaces = this.interfaceBuilders;
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
TypeBuilder interface = interfaces[i];
TypeDeclarationBuilder? declarationBuilder = interface.declaration;
if (declarationBuilder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declarationBuilder;
NamedTypeBuilder namedBuilder = interface as NamedTypeBuilder;
declarationBuilder = aliasBuilder.unaliasDeclaration(
namedBuilder.typeArguments,
isUsedAsClass: true,
usedAsClassCharOffset: namedBuilder.charOffset,
usedAsClassFileUri: namedBuilder.fileUri);
result[declarationBuilder] = aliasBuilder;
} else {
result[declarationBuilder] = null;
}
}
}
return result;
}
}
class _SourceExtensionTypeDeclarationBuilderAugmentationAccess
implements
ClassDeclarationAugmentationAccess<
SourceExtensionTypeDeclarationBuilder> {
const _SourceExtensionTypeDeclarationBuilderAugmentationAccess();
@override
SourceExtensionTypeDeclarationBuilder getOrigin(
SourceExtensionTypeDeclarationBuilder classDeclaration) =>
classDeclaration.origin;
@override
Iterable<SourceExtensionTypeDeclarationBuilder>? getAugmentations(
SourceExtensionTypeDeclarationBuilder classDeclaration) =>
null;
}