| // Copyright (c) 2019, 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:kernel/ast.dart'; |
| import 'package:kernel/type_algebra.dart'; |
| import 'package:kernel/type_environment.dart'; |
| |
| import '../base/modifiers.dart'; |
| import '../builder/builder.dart'; |
| import '../builder/declaration_builders.dart'; |
| import '../builder/formal_parameter_builder.dart'; |
| import '../builder/member_builder.dart'; |
| import '../builder/metadata_builder.dart'; |
| import '../builder/procedure_builder.dart'; |
| import '../builder/type_builder.dart'; |
| import '../kernel/augmentation_lowering.dart'; |
| import '../kernel/body_builder_context.dart'; |
| import '../kernel/hierarchy/class_member.dart'; |
| import '../kernel/hierarchy/members_builder.dart'; |
| import '../kernel/kernel_helper.dart'; |
| import '../kernel/member_covariance.dart'; |
| import 'name_scheme.dart'; |
| import 'source_builder_mixins.dart'; |
| import 'source_class_builder.dart'; |
| import 'source_extension_builder.dart'; |
| import 'source_extension_type_declaration_builder.dart'; |
| import 'source_function_builder.dart'; |
| import 'source_library_builder.dart' show SourceLibraryBuilder; |
| import 'source_loader.dart' show SourceLoader; |
| import 'source_member_builder.dart'; |
| |
| class SourceProcedureBuilder extends SourceFunctionBuilderImpl |
| implements ProcedureBuilder { |
| @override |
| final SourceLibraryBuilder libraryBuilder; |
| |
| final int charOpenParenOffset; |
| |
| AsyncMarker actualAsyncModifier = AsyncMarker.Sync; |
| |
| @override |
| final bool isExtensionInstanceMember; |
| |
| @override |
| final bool isExtensionTypeInstanceMember; |
| |
| @override |
| final TypeBuilder returnType; |
| |
| late Procedure _procedure; |
| |
| final Reference? _tearOffReference; |
| |
| /// If this is an extension instance method then [_extensionTearOff] holds |
| /// the synthetically created tear off function. |
| Procedure? _extensionTearOff; |
| |
| /// If this is an extension instance method then |
| /// [_extensionTearOffParameterMap] holds a map from the parameters of |
| /// the methods to the parameter of the closure returned in the tear-off. |
| /// |
| /// This map is used to set the default values on the closure parameters when |
| /// these have been built. |
| Map<VariableDeclaration, VariableDeclaration>? _extensionTearOffParameterMap; |
| |
| @override |
| final ProcedureKind kind; |
| |
| /// The builder for the original declaration. |
| SourceProcedureBuilder? _origin; |
| |
| /// If this builder is a patch or an augmentation, this is the builder for |
| /// the immediately augmented procedure. |
| SourceProcedureBuilder? _augmentedBuilder; |
| |
| int _augmentationIndex = 0; |
| |
| List<SourceProcedureBuilder>? _augmentations; |
| |
| final MemberName _memberName; |
| |
| SourceProcedureBuilder( |
| List<MetadataBuilder>? metadata, |
| Modifiers modifiers, |
| this.returnType, |
| String name, |
| List<NominalVariableBuilder>? typeVariables, |
| List<FormalParameterBuilder>? formals, |
| this.kind, |
| this.libraryBuilder, |
| DeclarationBuilder? declarationBuilder, |
| Uri fileUri, |
| int startCharOffset, |
| int charOffset, |
| this.charOpenParenOffset, |
| int charEndOffset, |
| Reference? procedureReference, |
| this._tearOffReference, |
| AsyncMarker asyncModifier, |
| NameScheme nameScheme, |
| {String? nativeMethodName, |
| bool isSynthetic = false}) |
| : assert(kind != ProcedureKind.Factory), |
| this.isExtensionInstanceMember = |
| nameScheme.isInstanceMember && nameScheme.isExtensionMember, |
| this.isExtensionTypeInstanceMember = |
| nameScheme.isInstanceMember && nameScheme.isExtensionTypeMember, |
| _memberName = nameScheme.getDeclaredName(name), |
| super( |
| metadata, |
| modifiers, |
| name, |
| typeVariables, |
| formals, |
| declarationBuilder ?? libraryBuilder, |
| fileUri, |
| charOffset, |
| nativeMethodName) { |
| _procedure = new Procedure( |
| dummyName, |
| isExtensionInstanceMember || isExtensionTypeInstanceMember |
| ? ProcedureKind.Method |
| : kind, |
| new FunctionNode(null), |
| fileUri: fileUri, |
| reference: procedureReference, |
| isSynthetic: isSynthetic) |
| ..fileStartOffset = startCharOffset |
| ..fileOffset = charOffset |
| ..fileEndOffset = charEndOffset; |
| nameScheme.getProcedureMemberName(kind, name).attachMember(_procedure); |
| this.asyncModifier = asyncModifier; |
| if ((isExtensionInstanceMember || isExtensionTypeInstanceMember) && |
| kind == ProcedureKind.Method) { |
| _extensionTearOff = new Procedure( |
| dummyName, ProcedureKind.Method, new FunctionNode(null), |
| isStatic: true, |
| isExtensionMember: isExtensionInstanceMember, |
| isExtensionTypeMember: isExtensionTypeInstanceMember, |
| reference: _tearOffReference, |
| fileUri: fileUri); |
| nameScheme |
| .getProcedureMemberName(ProcedureKind.Getter, name) |
| .attachMember(_extensionTearOff!); |
| } |
| } |
| |
| @override |
| Name get memberName => _memberName.name; |
| |
| // Coverage-ignore(suite): Not run. |
| List<SourceProcedureBuilder>? get augmentationsForTesting => _augmentations; |
| |
| @override |
| AsyncMarker get asyncModifier => actualAsyncModifier; |
| |
| @override |
| Statement? get body { |
| if (bodyInternal == null && !isAbstract && !isExternal) { |
| bodyInternal = new EmptyStatement(); |
| } |
| return bodyInternal; |
| } |
| |
| void set asyncModifier(AsyncMarker newModifier) { |
| actualAsyncModifier = newModifier; |
| function.asyncMarker = actualAsyncModifier; |
| function.dartAsyncMarker = actualAsyncModifier; |
| } |
| |
| bool get isExtensionMethod { |
| return parent is SourceExtensionBuilder; |
| } |
| |
| bool get isExtensionTypeMethod { |
| return parent is SourceExtensionTypeDeclarationBuilder; |
| } |
| |
| @override |
| Member get member => procedure; |
| |
| @override |
| SourceProcedureBuilder get origin => _origin ?? this; |
| |
| @override |
| Procedure get procedure => isAugmenting ? origin.procedure : _procedure; |
| |
| Procedure get actualProcedure => _procedure; |
| |
| Procedure? _augmentedProcedure; |
| |
| @override |
| FunctionNode get function => _procedure.function; |
| |
| bool _typeEnsured = false; |
| Set<ClassMember>? _overrideDependencies; |
| |
| void registerOverrideDependency(Set<ClassMember> overriddenMembers) { |
| assert( |
| overriddenMembers.every((overriddenMember) => |
| overriddenMember.declarationBuilder != classBuilder), |
| "Unexpected override dependencies for $this: $overriddenMembers"); |
| _overrideDependencies ??= {}; |
| _overrideDependencies!.addAll(overriddenMembers); |
| } |
| |
| void _ensureTypes(ClassMembersBuilder membersBuilder) { |
| if (_typeEnsured) return; |
| if (_overrideDependencies != null) { |
| if (isGetter) { |
| membersBuilder.inferGetterType(this, _overrideDependencies!); |
| } else if (isSetter) { |
| membersBuilder.inferSetterType(this, _overrideDependencies!); |
| } else { |
| membersBuilder.inferMethodType(this, _overrideDependencies!); |
| } |
| _overrideDependencies = null; |
| } |
| returnType.build(libraryBuilder, TypeUse.fieldType, |
| hierarchy: membersBuilder.hierarchyBuilder); |
| if (formals != null) { |
| for (FormalParameterBuilder formal in formals!) { |
| formal.type.build(libraryBuilder, TypeUse.parameterType, |
| hierarchy: membersBuilder.hierarchyBuilder); |
| } |
| } |
| _typeEnsured = true; |
| } |
| |
| @override |
| Member? get readTarget { |
| switch (kind) { |
| case ProcedureKind.Method: |
| return extensionTearOff ?? procedure; |
| case ProcedureKind.Getter: |
| return procedure; |
| case ProcedureKind.Factory: |
| // Coverage-ignore(suite): Not run. |
| return procedure; |
| case ProcedureKind.Operator: |
| case ProcedureKind.Setter: |
| return null; |
| } |
| } |
| |
| @override |
| Member? get writeTarget { |
| switch (kind) { |
| case ProcedureKind.Setter: |
| return procedure; |
| // Coverage-ignore(suite): Not run. |
| case ProcedureKind.Method: |
| case ProcedureKind.Getter: |
| case ProcedureKind.Operator: |
| case ProcedureKind.Factory: |
| return null; |
| } |
| } |
| |
| @override |
| Member? get invokeTarget { |
| switch (kind) { |
| case ProcedureKind.Method: |
| case ProcedureKind.Getter: |
| case ProcedureKind.Operator: |
| case ProcedureKind.Factory: |
| return procedure; |
| case ProcedureKind.Setter: |
| return null; |
| } |
| } |
| |
| @override |
| Iterable<Member> get exportedMembers => [procedure]; |
| |
| @override |
| void buildOutlineNodes(BuildNodesCallback f) { |
| _build(); |
| if (isExtensionMethod) { |
| switch (kind) { |
| case ProcedureKind.Method: |
| f( |
| member: _procedure, |
| tearOff: extensionTearOff, |
| kind: BuiltMemberKind.ExtensionMethod); |
| break; |
| case ProcedureKind.Getter: |
| assert(extensionTearOff == null, "Unexpected extension tear-off."); |
| f(member: _procedure, kind: BuiltMemberKind.ExtensionGetter); |
| break; |
| case ProcedureKind.Setter: |
| assert(extensionTearOff == null, "Unexpected extension tear-off."); |
| f(member: _procedure, kind: BuiltMemberKind.ExtensionSetter); |
| break; |
| case ProcedureKind.Operator: |
| assert(extensionTearOff == null, "Unexpected extension tear-off."); |
| f(member: _procedure, kind: BuiltMemberKind.ExtensionOperator); |
| break; |
| // Coverage-ignore(suite): Not run. |
| case ProcedureKind.Factory: |
| throw new UnsupportedError( |
| 'Unexpected extension method kind ${kind}'); |
| } |
| } else if (isExtensionTypeMethod) { |
| switch (kind) { |
| case ProcedureKind.Method: |
| f( |
| member: _procedure, |
| tearOff: extensionTearOff, |
| kind: BuiltMemberKind.ExtensionTypeMethod); |
| break; |
| case ProcedureKind.Getter: |
| assert(extensionTearOff == null, "Unexpected extension tear-off."); |
| f(member: _procedure, kind: BuiltMemberKind.ExtensionTypeGetter); |
| break; |
| case ProcedureKind.Setter: |
| assert(extensionTearOff == null, "Unexpected extension tear-off."); |
| f(member: _procedure, kind: BuiltMemberKind.ExtensionTypeSetter); |
| break; |
| case ProcedureKind.Operator: |
| assert(extensionTearOff == null, "Unexpected extension tear-off."); |
| f(member: _procedure, kind: BuiltMemberKind.ExtensionTypeOperator); |
| break; |
| // Coverage-ignore(suite): Not run. |
| case ProcedureKind.Factory: |
| f( |
| member: _procedure, |
| tearOff: extensionTearOff, |
| kind: BuiltMemberKind.ExtensionTypeFactory); |
| break; |
| } |
| } else { |
| f(member: member, kind: BuiltMemberKind.Method); |
| } |
| } |
| |
| void _build() { |
| buildFunction(); |
| _procedure.function.fileOffset = charOpenParenOffset; |
| _procedure.function.fileEndOffset = _procedure.fileEndOffset; |
| _procedure.isAbstract = isAbstract; |
| _procedure.isExternal = isExternal; |
| _procedure.isConst = isConst; |
| if (isExtensionMethod) { |
| _procedure.isExtensionMember = true; |
| _procedure.isStatic = true; |
| if (isExtensionInstanceMember) { |
| assert(_procedure.kind == ProcedureKind.Method); |
| } |
| } else if (isExtensionTypeMethod) { |
| _procedure.isExtensionTypeMember = true; |
| _procedure.isStatic = true; |
| if (isExtensionTypeInstanceMember) { |
| assert(_procedure.kind == ProcedureKind.Method); |
| } |
| } else { |
| _procedure.isStatic = isStatic; |
| } |
| if (extensionTearOff != null) { |
| _buildExtensionTearOff( |
| libraryBuilder, parent as SourceDeclarationBuilderMixin); |
| } |
| } |
| |
| /// Creates a top level function that creates a tear off of an extension |
| /// instance method. |
| /// |
| /// For this declaration |
| /// |
| /// extension E<T> on A<T> { |
| /// X method<S>(S s, Y y) {} |
| /// } |
| /// |
| /// we create the top level function |
| /// |
| /// X E|method<T, S>(A<T> #this, S s, Y y) {} |
| /// |
| /// and the tear off function |
| /// |
| /// X Function<S>(S, Y) E|get#method<T>(A<T> #this) { |
| /// return (S s, Y y) => E|method<T, S>(#this, s, y); |
| /// } |
| /// |
| void _buildExtensionTearOff(SourceLibraryBuilder sourceLibraryBuilder, |
| SourceDeclarationBuilderMixin declarationBuilder) { |
| assert( |
| _extensionTearOff != null, "No extension tear off created for $this."); |
| |
| _extensionTearOffParameterMap = {}; |
| |
| int fileOffset = _procedure.fileOffset; |
| int fileEndOffset = _procedure.fileEndOffset; |
| |
| int extensionTypeParameterCount = |
| declarationBuilder.typeParameters?.length ?? 0; |
| |
| List<TypeParameter> typeParameters = <TypeParameter>[]; |
| |
| Map<TypeParameter, DartType> substitutionMap = {}; |
| List<DartType> typeArguments = <DartType>[]; |
| for (TypeParameter typeParameter in function.typeParameters) { |
| TypeParameter newTypeParameter = new TypeParameter(typeParameter.name); |
| typeParameters.add(newTypeParameter); |
| typeArguments.add(substitutionMap[typeParameter] = |
| new TypeParameterType.forAlphaRenaming( |
| typeParameter, newTypeParameter)); |
| } |
| |
| List<TypeParameter> tearOffTypeParameters = <TypeParameter>[]; |
| List<TypeParameter> closureTypeParameters = <TypeParameter>[]; |
| Substitution substitution = Substitution.fromMap(substitutionMap); |
| for (int index = 0; index < typeParameters.length; index++) { |
| TypeParameter newTypeParameter = typeParameters[index]; |
| newTypeParameter.bound = |
| substitution.substituteType(function.typeParameters[index].bound); |
| newTypeParameter.defaultType = function.typeParameters[index].defaultType; |
| if (index < extensionTypeParameterCount) { |
| tearOffTypeParameters.add(newTypeParameter); |
| } else { |
| closureTypeParameters.add(newTypeParameter); |
| } |
| } |
| |
| VariableDeclaration copyParameter( |
| VariableDeclaration parameter, DartType type) { |
| VariableDeclaration newParameter = new VariableDeclaration(parameter.name, |
| type: type, |
| isFinal: parameter.isFinal, |
| isLowered: parameter.isLowered, |
| isRequired: parameter.isRequired) |
| ..fileOffset = parameter.fileOffset; |
| _extensionTearOffParameterMap![parameter] = newParameter; |
| return newParameter; |
| } |
| |
| VariableDeclaration extensionThis = copyParameter( |
| function.positionalParameters.first, |
| substitution.substituteType(function.positionalParameters.first.type)); |
| |
| DartType closureReturnType = |
| substitution.substituteType(function.returnType); |
| List<VariableDeclaration> closurePositionalParameters = []; |
| List<Expression> closurePositionalArguments = []; |
| |
| for (int position = 0; |
| position < function.positionalParameters.length; |
| position++) { |
| VariableDeclaration parameter = function.positionalParameters[position]; |
| if (position == 0) { |
| /// Pass `this` as a captured variable. |
| closurePositionalArguments |
| .add(new VariableGet(extensionThis)..fileOffset = fileOffset); |
| } else { |
| DartType type = substitution.substituteType(parameter.type); |
| VariableDeclaration newParameter = copyParameter(parameter, type); |
| closurePositionalParameters.add(newParameter); |
| closurePositionalArguments |
| .add(new VariableGet(newParameter)..fileOffset = fileOffset); |
| } |
| } |
| List<VariableDeclaration> closureNamedParameters = []; |
| List<NamedExpression> closureNamedArguments = []; |
| for (VariableDeclaration parameter in function.namedParameters) { |
| DartType type = substitution.substituteType(parameter.type); |
| VariableDeclaration newParameter = copyParameter(parameter, type); |
| closureNamedParameters.add(newParameter); |
| closureNamedArguments.add(new NamedExpression(parameter.name!, |
| new VariableGet(newParameter)..fileOffset = fileOffset)); |
| } |
| |
| Statement closureBody = new ReturnStatement( |
| new StaticInvocation( |
| _procedure, |
| new Arguments(closurePositionalArguments, |
| types: typeArguments, named: closureNamedArguments)) |
| ..fileOffset = fileOffset) |
| ..fileOffset = fileOffset; |
| |
| FunctionExpression closure = new FunctionExpression( |
| new FunctionNode(closureBody, |
| typeParameters: closureTypeParameters, |
| positionalParameters: closurePositionalParameters, |
| namedParameters: closureNamedParameters, |
| requiredParameterCount: |
| _procedure.function.requiredParameterCount - 1, |
| returnType: closureReturnType) |
| ..fileOffset = fileOffset |
| ..fileEndOffset = fileEndOffset) |
| ..fileOffset = fileOffset; |
| |
| _extensionTearOff! |
| ..function = (new FunctionNode( |
| new ReturnStatement(closure)..fileOffset = fileOffset, |
| typeParameters: tearOffTypeParameters, |
| positionalParameters: [extensionThis], |
| requiredParameterCount: 1, |
| returnType: |
| closure.function.computeFunctionType(Nullability.nonNullable)) |
| ..fileOffset = fileOffset |
| ..fileEndOffset = fileEndOffset) |
| ..fileUri = fileUri |
| ..fileOffset = fileOffset |
| ..fileEndOffset = fileEndOffset; |
| _extensionTearOff!.function.parent = _extensionTearOff; |
| } |
| |
| Procedure? get extensionTearOff => _extensionTearOff; |
| |
| @override |
| VariableDeclaration? getTearOffParameter(int index) { |
| return _extensionTearOffParameterMap?[getFormalParameter(index)]; |
| } |
| |
| List<ClassMember>? _localMembers; |
| List<ClassMember>? _localSetters; |
| |
| @override |
| List<ClassMember> get localMembers => _localMembers ??= isSetter |
| ? const <ClassMember>[] |
| : <ClassMember>[ |
| new SourceProcedureMember( |
| this, isGetter ? ClassMemberKind.Getter : ClassMemberKind.Method) |
| ]; |
| |
| @override |
| List<ClassMember> get localSetters => |
| _localSetters ??= isSetter && !isConflictingSetter |
| ? <ClassMember>[ |
| new SourceProcedureMember(this, ClassMemberKind.Setter) |
| ] |
| : const <ClassMember>[]; |
| |
| @override |
| void becomeNative(SourceLoader loader) { |
| _procedure.isExternal = true; |
| super.becomeNative(loader); |
| } |
| |
| @override |
| void applyAugmentation(Builder augmentation) { |
| if (augmentation is SourceProcedureBuilder) { |
| if (checkAugmentation(augmentation)) { |
| augmentation._origin = this; |
| SourceProcedureBuilder augmentedBuilder = |
| _augmentations == null ? this : _augmentations!.last; |
| augmentation._augmentedBuilder = augmentedBuilder; |
| augmentation._augmentationIndex = |
| augmentedBuilder._augmentationIndex + 1; |
| (_augmentations ??= []).add(augmentation); |
| } |
| } else { |
| // Coverage-ignore-block(suite): Not run. |
| reportAugmentationMismatch(augmentation); |
| } |
| } |
| |
| Map<SourceProcedureBuilder, AugmentSuperTarget?> _augmentedProcedures = {}; |
| |
| AugmentSuperTarget? _createAugmentSuperTarget( |
| SourceProcedureBuilder? targetBuilder) { |
| if (targetBuilder == null) return null; |
| Procedure declaredProcedure = targetBuilder.actualProcedure; |
| |
| if (declaredProcedure.isAbstract || declaredProcedure.isExternal) { |
| // Coverage-ignore-block(suite): Not run. |
| return targetBuilder._augmentedBuilder != null |
| ? _getAugmentSuperTarget(targetBuilder._augmentedBuilder!) |
| : null; |
| } |
| |
| Procedure augmentedProcedure = |
| targetBuilder._augmentedProcedure = new Procedure( |
| augmentedName(declaredProcedure.name.text, libraryBuilder.library, |
| targetBuilder._augmentationIndex), |
| declaredProcedure.kind, |
| declaredProcedure.function, |
| fileUri: declaredProcedure.fileUri) |
| ..flags = declaredProcedure.flags |
| ..isStatic = procedure.isStatic |
| ..parent = procedure.parent |
| ..isInternalImplementation = true; |
| |
| Member? readTarget; |
| Member? invokeTarget; |
| Member? writeTarget; |
| switch (kind) { |
| case ProcedureKind.Method: |
| readTarget = extensionTearOff ?? augmentedProcedure; |
| invokeTarget = augmentedProcedure; |
| break; |
| case ProcedureKind.Getter: |
| readTarget = augmentedProcedure; |
| invokeTarget = augmentedProcedure; |
| break; |
| case ProcedureKind.Factory: |
| readTarget = augmentedProcedure; |
| invokeTarget = augmentedProcedure; |
| break; |
| case ProcedureKind.Operator: |
| invokeTarget = augmentedProcedure; |
| break; |
| case ProcedureKind.Setter: |
| writeTarget = augmentedProcedure; |
| break; |
| } |
| return new AugmentSuperTarget( |
| declaration: targetBuilder, |
| readTarget: readTarget, |
| invokeTarget: invokeTarget, |
| writeTarget: writeTarget); |
| } |
| |
| AugmentSuperTarget? _getAugmentSuperTarget( |
| SourceProcedureBuilder augmentation) { |
| return _augmentedProcedures[augmentation] ??= |
| _createAugmentSuperTarget(augmentation._augmentedBuilder); |
| } |
| |
| @override |
| AugmentSuperTarget? get augmentSuperTarget => |
| origin._getAugmentSuperTarget(this); |
| |
| @override |
| int buildBodyNodes(BuildNodesCallback f) { |
| List<SourceProcedureBuilder>? augmentations = _augmentations; |
| if (augmentations != null) { |
| void addAugmentedProcedure(SourceProcedureBuilder builder) { |
| Procedure? augmentedProcedure = builder._augmentedProcedure; |
| if (augmentedProcedure != null) { |
| augmentedProcedure |
| ..fileOffset = builder.actualProcedure.fileOffset |
| ..fileEndOffset = builder.actualProcedure.fileEndOffset |
| ..fileStartOffset = builder.actualProcedure.fileStartOffset |
| ..signatureType = builder.actualProcedure.signatureType |
| ..flags = builder.actualProcedure.flags; |
| f(member: augmentedProcedure, kind: BuiltMemberKind.Method); |
| } |
| } |
| |
| addAugmentedProcedure(this); |
| for (SourceProcedureBuilder augmentation in augmentations) { |
| addAugmentedProcedure(augmentation); |
| } |
| finishProcedureAugmentation( |
| procedure, augmentations.last.actualProcedure); |
| |
| return augmentations.length; |
| } |
| return 0; |
| } |
| |
| @override |
| void checkVariance( |
| SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { |
| sourceClassBuilder.checkVarianceInFunction( |
| procedure, typeEnvironment, sourceClassBuilder.cls.typeParameters); |
| List<SourceProcedureBuilder>? augmentations = _augmentations; |
| if (augmentations != null) { |
| for (SourceProcedureBuilder augmentation in augmentations) { |
| augmentation.checkVariance(sourceClassBuilder, typeEnvironment); |
| } |
| } |
| } |
| |
| @override |
| void checkTypes( |
| SourceLibraryBuilder library, TypeEnvironment typeEnvironment) { |
| library.checkTypesInFunctionBuilder(this, typeEnvironment); |
| List<SourceProcedureBuilder>? augmentations = _augmentations; |
| if (augmentations != null) { |
| for (SourceProcedureBuilder augmentation in augmentations) { |
| augmentation.checkTypes(library, typeEnvironment); |
| } |
| } |
| } |
| |
| @override |
| BodyBuilderContext createBodyBuilderContext( |
| {required bool inOutlineBuildingPhase, |
| required bool inMetadata, |
| required bool inConstFields}) { |
| return new ProcedureBodyBuilderContext(this, |
| inOutlineBuildingPhase: inOutlineBuildingPhase, |
| inMetadata: inMetadata, |
| inConstFields: inConstFields); |
| } |
| |
| // TODO(johnniwinther): Add annotations to tear-offs. |
| @override |
| Iterable<Annotatable> get annotatables => [procedure]; |
| |
| @override |
| bool get isAugmented { |
| if (isAugmenting) { |
| return origin._augmentations!.last != this; |
| } else { |
| return _augmentations != null; |
| } |
| } |
| } |
| |
| class SourceProcedureMember extends BuilderClassMember { |
| @override |
| final SourceProcedureBuilder memberBuilder; |
| |
| @override |
| final ClassMemberKind memberKind; |
| |
| Covariance? _covariance; |
| |
| SourceProcedureMember(this.memberBuilder, this.memberKind); |
| |
| @override |
| bool get isSourceDeclaration => true; |
| |
| @override |
| void inferType(ClassMembersBuilder membersBuilder) { |
| memberBuilder._ensureTypes(membersBuilder); |
| } |
| |
| @override |
| void registerOverrideDependency(Set<ClassMember> overriddenMembers) { |
| memberBuilder.registerOverrideDependency(overriddenMembers); |
| } |
| |
| @override |
| Member getMember(ClassMembersBuilder membersBuilder) { |
| memberBuilder._ensureTypes(membersBuilder); |
| return memberBuilder.member; |
| } |
| |
| @override |
| Member? getTearOff(ClassMembersBuilder membersBuilder) { |
| // Ensure function type is computed. |
| getMember(membersBuilder); |
| Member? readTarget = memberBuilder.readTarget; |
| return readTarget != memberBuilder.invokeTarget ? readTarget : null; |
| } |
| |
| @override |
| Covariance getCovariance(ClassMembersBuilder membersBuilder) { |
| return _covariance ??= new Covariance.fromMember(getMember(membersBuilder), |
| forSetter: forSetter); |
| } |
| |
| @override |
| bool isSameDeclaration(ClassMember other) { |
| return other is SourceProcedureMember && |
| memberBuilder == other.memberBuilder; |
| } |
| } |