| // Copyright (c) 2018, 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/clone.dart' show CloneVisitorNotMembers; |
| import 'package:kernel/core_types.dart' show CoreTypes; |
| import 'package:kernel/reference_from_index.dart'; |
| import 'package:kernel/src/nnbd_top_merge.dart'; |
| import 'package:kernel/src/norm.dart'; |
| import 'package:kernel/src/types.dart' show Types; |
| import 'package:kernel/type_algebra.dart'; |
| |
| import '../base/problems.dart' show unhandled; |
| import '../builder/declaration_builders.dart'; |
| import '../source/source_class_builder.dart'; |
| import 'hierarchy/class_member.dart'; |
| import 'hierarchy/hierarchy_builder.dart'; |
| import 'hierarchy/members_builder.dart'; |
| import 'member_covariance.dart'; |
| |
| /// Class used for computing and inspecting the combined member signature for |
| /// a set of overridden/inherited [ClassMember]s. |
| abstract class CombinedMemberSignatureBase { |
| /// The class members builder used for building this class. |
| final ClassMembersBuilder membersBuilder; |
| |
| /// The list of the members inherited into or overridden in |
| /// [extensionTypeDeclarationBuilder]. |
| final List<ClassMember> members; |
| |
| /// The target declaration for the combined member signature. |
| /// |
| /// The [_memberTypes] are computed in terms of each member is inherited into |
| /// [declarationBuilder]. |
| /// |
| /// [declarationBuilder] is also used for determining whether the combined |
| /// member signature should be computed using nnbd or legacy semantics. |
| DeclarationBuilder get declarationBuilder; |
| |
| /// If `true` the combined member signature is for the setter aspect of the |
| /// members. Otherwise it is for the getter/method aspect of the members. |
| final bool forSetter; |
| |
| /// The index within [members] for the member whose type is the most specific |
| /// among [members]. If `null`, the combined member signature is not defined |
| /// for [members] in [extensionTypeDeclarationBuilder]. |
| /// |
| /// For the legacy computation, the type of this member defines the combined |
| /// member signature. |
| /// |
| /// For the nnbd computation, this is one of the members whose type define |
| /// the combined member signature, and the indices of the remaining members |
| /// are stored in [_mutualSubtypes]. |
| int? _canonicalMemberIndex; |
| |
| /// For the nnbd computation, this maps each distinct but most specific member |
| /// type to the index of one of the [members] with that type. |
| /// |
| /// If there is only one most specific member type, this is `null`. |
| Map<DartType, int>? _mutualSubtypes; |
| |
| /// Cache for the types of [members] as inherited into |
| /// [extensionTypeDeclarationBuilder]. |
| List<DartType?>? _memberTypes; |
| |
| /// If `true` the combined member signature type has been computed. |
| /// |
| /// Note that the combined member signature type might be undefined in which |
| /// case [_combinedMemberSignatureType] is `null`. |
| bool _isCombinedMemberSignatureTypeComputed = false; |
| |
| /// Cache the computed combined member signature type. |
| /// |
| /// If the combined member signature type is undefined this is set to `null`. |
| DartType? _combinedMemberSignatureType; |
| |
| /// The indices for the members whose type needed legacy erasure. |
| /// |
| /// This is fully computed when [combinedMemberSignatureType] has been |
| /// computed. |
| Set<int>? _neededLegacyErasureIndices; |
| |
| bool _neededNnbdTopMerge = false; |
| |
| bool _needsCovarianceMerging = false; |
| |
| bool _isCombinedMemberSignatureCovarianceComputed = false; |
| |
| Covariance? _combinedMemberSignatureCovariance; |
| |
| /// Creates a [CombinedMemberSignatureBase] whose canonical member is already |
| /// defined. |
| CombinedMemberSignatureBase.internal( |
| this.membersBuilder, |
| this._canonicalMemberIndex, |
| this.members, { |
| required this.forSetter, |
| }); |
| |
| /// Creates a [CombinedMemberSignatureBase] for [members] inherited into |
| /// [extensionTypeDeclarationBuilder]. |
| /// |
| /// If [forSetter] is `true`, contravariance of the setter types is used to |
| /// compute the most specific member type. Otherwise covariance of the getter |
| /// types or function types is used. |
| CombinedMemberSignatureBase( |
| this.membersBuilder, |
| this.members, { |
| required this.forSetter, |
| }) { |
| int? bestSoFarIndex; |
| if (members.length == 1) { |
| bestSoFarIndex = 0; |
| } else { |
| DartType? bestTypeSoFar; |
| for ( |
| int candidateIndex = members.length - 1; |
| candidateIndex >= 0; |
| candidateIndex-- |
| ) { |
| DartType candidateType = getMemberType(candidateIndex); |
| if (bestSoFarIndex == null) { |
| bestTypeSoFar = candidateType; |
| bestSoFarIndex = candidateIndex; |
| } else { |
| if (_isMoreSpecific(candidateType, bestTypeSoFar!, forSetter)) { |
| if (_isMoreSpecific(bestTypeSoFar, candidateType, forSetter)) { |
| if (_mutualSubtypes == null) { |
| _mutualSubtypes = { |
| bestTypeSoFar: bestSoFarIndex, |
| candidateType: candidateIndex, |
| }; |
| } else { |
| _mutualSubtypes![candidateType] = candidateIndex; |
| } |
| } else { |
| _mutualSubtypes = null; |
| } |
| bestSoFarIndex = candidateIndex; |
| bestTypeSoFar = candidateType; |
| } |
| } |
| } |
| if (_mutualSubtypes?.length == 1) { |
| /// If all mutual subtypes have the same type, the type should not |
| /// be normalized. |
| _mutualSubtypes = null; |
| } |
| if (bestSoFarIndex != null) { |
| for ( |
| int candidateIndex = 0; |
| candidateIndex < members.length; |
| candidateIndex++ |
| ) { |
| DartType candidateType = getMemberType(candidateIndex); |
| if (!_isMoreSpecific(bestTypeSoFar!, candidateType, forSetter)) { |
| int? favoredIndex = getOverlookedOverrideProblemChoice( |
| declarationBuilder, |
| ); |
| bestSoFarIndex = favoredIndex; |
| _mutualSubtypes = null; |
| break; |
| } |
| } |
| } |
| } |
| |
| _canonicalMemberIndex = bestSoFarIndex; |
| } |
| |
| /// The member within [members] type is the most specific among [members]. |
| /// If `null`, the combined member signature is not defined for [members] in |
| /// [extensionTypeDeclarationBuilder]. |
| /// |
| /// For the legacy computation, the type of this member defines the combined |
| /// member signature. |
| /// |
| /// For the nnbd computation, this is one of the members whose type define |
| /// the combined member signature, and the indices of the all members whose |
| /// type define the combined member signature are in [mutualSubtypeIndices]. |
| ClassMember? get canonicalMember => |
| _canonicalMemberIndex != null ? members[_canonicalMemberIndex!] : null; |
| |
| /// The index within [members] for the member whose type is the most specific |
| /// among [members]. If `null`, the combined member signature is not defined |
| /// for [members] in [extensionTypeDeclarationBuilder]. |
| /// |
| /// For the legacy computation, the type of this member defines the combined |
| /// member signature. |
| /// |
| /// For the nnbd computation, this is one of the members whose type define |
| /// the combined member signature, and the indices of the all members whose |
| /// type define the combined member signature are in [mutualSubtypeIndices]. |
| int? get canonicalMemberIndex => _canonicalMemberIndex; |
| |
| ClassHierarchyBuilder get hierarchy => membersBuilder.hierarchyBuilder; |
| |
| CoreTypes get _coreTypes => hierarchy.coreTypes; |
| |
| Types get _types => hierarchy.types; |
| |
| Member _getMember(int index) { |
| ClassMember candidate = members[index]; |
| return candidate.getMember(membersBuilder); |
| } |
| |
| /// Returns `true` if legacy erasure was needed to compute the combined |
| /// member signature type. |
| /// |
| /// Legacy erasure is considered need of if the used of it resulted in a |
| /// different type. |
| bool get neededLegacyErasure { |
| _ensureCombinedMemberSignatureType(); |
| return _neededLegacyErasureIndices |
| // Coverage-ignore(suite): Not run. |
| ?.contains(canonicalMemberIndex) ?? |
| false; |
| } |
| |
| /// Returns `true` if nnbd top merge and normalization was needed to compute |
| /// the combined member signature type. |
| bool get neededNnbdTopMerge { |
| _ensureCombinedMemberSignatureType(); |
| return _neededNnbdTopMerge; |
| } |
| |
| /// Returns the this type of the [declarationBuilder]. |
| TypeDeclarationType get thisType; |
| |
| /// Returns `true` if the canonical member is declared in |
| /// [declarationBuilder]. |
| bool get isCanonicalMemberDeclared; |
| |
| /// Returns `true` if the canonical member is the 0th. |
| // TODO(johnniwinther): This is currently used under the assumption that the |
| // 0th member is either from the superclass or the one found if looked up |
| // the class hierarchy. This is a very brittle assumption. |
| bool get isCanonicalMemberFirst => _canonicalMemberIndex == 0; |
| |
| /// Returns type of the [index]th member in [members] as inherited in |
| /// [extensionTypeDeclarationBuilder]. |
| DartType getMemberType(int index) { |
| _memberTypes ??= new List<DartType?>.filled(members.length, null); |
| DartType? candidateType = _memberTypes![index]; |
| if (candidateType == null) { |
| Member target = _getMember(index); |
| candidateType = _computeMemberType(target); |
| _memberTypes![index] = candidateType; |
| } |
| return candidateType; |
| } |
| |
| DartType getMemberTypeForTarget(Member target) { |
| return _computeMemberType(target); |
| } |
| |
| void _ensureCombinedMemberSignatureType() { |
| if (!_isCombinedMemberSignatureTypeComputed) { |
| _isCombinedMemberSignatureTypeComputed = true; |
| if (_canonicalMemberIndex == null) { |
| return null; |
| } |
| DartType canonicalMemberType = _combinedMemberSignatureType = |
| getMemberType(_canonicalMemberIndex!); |
| if (_mutualSubtypes != null) { |
| _combinedMemberSignatureType = norm( |
| _coreTypes, |
| _combinedMemberSignatureType!, |
| ); |
| for (int index in _mutualSubtypes!.values) { |
| if (_canonicalMemberIndex != index) { |
| _combinedMemberSignatureType = nnbdTopMerge( |
| _coreTypes, |
| _combinedMemberSignatureType!, |
| norm(_coreTypes, getMemberType(index)), |
| ); |
| assert( |
| _combinedMemberSignatureType != null, |
| "No combined member signature found for " |
| "${_mutualSubtypes!.values.map((int i) => getMemberType(i))} " |
| "for members ${members}", |
| ); |
| } |
| } |
| _neededNnbdTopMerge = |
| canonicalMemberType != _combinedMemberSignatureType; |
| } |
| } |
| } |
| |
| /// Returns the type of the combined member signature, if defined. |
| DartType? get combinedMemberSignatureType { |
| _ensureCombinedMemberSignatureType(); |
| return _combinedMemberSignatureType; |
| } |
| |
| Covariance _getMemberCovariance(int index) { |
| ClassMember candidate = members[index]; |
| return candidate.getCovariance(membersBuilder); |
| } |
| |
| void _ensureCombinedMemberSignatureCovariance() { |
| if (!_isCombinedMemberSignatureCovarianceComputed) { |
| _isCombinedMemberSignatureCovarianceComputed = true; |
| if (canonicalMemberIndex == null) { |
| return; |
| } |
| Covariance canonicalMemberCovariance = |
| _combinedMemberSignatureCovariance = _getMemberCovariance( |
| canonicalMemberIndex!, |
| ); |
| if (members.length == 1) { |
| return; |
| } |
| for (int index = 0; index < members.length; index++) { |
| if (index != canonicalMemberIndex) { |
| _combinedMemberSignatureCovariance = |
| _combinedMemberSignatureCovariance!.merge( |
| _getMemberCovariance(index), |
| ); |
| } |
| } |
| _needsCovarianceMerging = |
| canonicalMemberCovariance != _combinedMemberSignatureCovariance; |
| } |
| } |
| |
| // Returns `true` if the covariance of [members] needs to be merged into |
| // the combined member signature. |
| bool get needsCovarianceMerging { |
| if (members.length != 1) { |
| _ensureCombinedMemberSignatureCovariance(); |
| } |
| return _needsCovarianceMerging; |
| } |
| |
| /// Returns [Covariance] for the combined member signature. |
| Covariance? get combinedMemberSignatureCovariance { |
| _ensureCombinedMemberSignatureCovariance(); |
| return _combinedMemberSignatureCovariance; |
| } |
| |
| /// Returns the type of the combined member signature, if defined, with |
| /// all method type parameters substituted with [typeParameters]. |
| /// |
| /// This is used for inferring types on a declared member from the type of the |
| /// combined member signature. |
| DartType? getCombinedSignatureTypeInContext( |
| List<TypeParameter> typeParameters, |
| ) { |
| DartType? type = combinedMemberSignatureType; |
| if (type == null) { |
| return null; |
| } |
| int typeParameterCount = typeParameters.length; |
| if (type is FunctionType) { |
| List<StructuralParameter> signatureTypeParameters = type.typeParameters; |
| if (typeParameterCount != signatureTypeParameters.length) { |
| return null; |
| } |
| if (typeParameterCount == 0) { |
| return type; |
| } |
| List<DartType> types = [ |
| for (TypeParameter parameter in typeParameters) |
| new TypeParameterType.withDefaultNullability(parameter), |
| ]; |
| FunctionTypeInstantiator instantiator = |
| new FunctionTypeInstantiator.fromIterables( |
| signatureTypeParameters, |
| types, |
| ); |
| for (int i = 0; i < typeParameterCount; i++) { |
| DartType typeParameterBound = typeParameters[i].bound; |
| DartType signatureTypeParameterBound = instantiator.substitute( |
| signatureTypeParameters[i].bound, |
| ); |
| if (!_types |
| .performMutualSubtypesCheck( |
| typeParameterBound, |
| signatureTypeParameterBound, |
| ) |
| .isSuccess()) { |
| return null; |
| } |
| } |
| return instantiator.substitute(type.withoutTypeParameters); |
| } |
| // Coverage-ignore(suite): Not run. |
| else if (typeParameterCount != 0) { |
| return null; |
| } |
| return type; |
| } |
| |
| /// Create a member signature with the [combinedMemberSignatureType] using the |
| /// [canonicalMember] as member signature origin. |
| Procedure? createMemberFromSignature( |
| FileUriNode declarationNode, |
| IndexedContainer? indexedContainer, { |
| bool copyLocation = true, |
| }) { |
| if (canonicalMemberIndex == null) { |
| return null; |
| } |
| Member member = _getMember(canonicalMemberIndex!); |
| Procedure combinedMemberSignature; |
| if (member is Procedure) { |
| switch (member.kind) { |
| case ProcedureKind.Getter: |
| combinedMemberSignature = _createGetterMemberSignature( |
| declarationNode, |
| indexedContainer, |
| member, |
| combinedMemberSignatureType!, |
| copyLocation: copyLocation, |
| ); |
| break; |
| case ProcedureKind.Setter: |
| VariableDeclaration parameter = |
| member.function.positionalParameters.first; |
| combinedMemberSignature = _createSetterMemberSignature( |
| declarationNode, |
| indexedContainer, |
| member, |
| combinedMemberSignatureType!, |
| isCovariantByClass: parameter.isCovariantByClass, |
| isCovariantByDeclaration: parameter.isCovariantByDeclaration, |
| parameter: parameter, |
| copyLocation: copyLocation, |
| ); |
| break; |
| case ProcedureKind.Method: |
| case ProcedureKind.Operator: |
| combinedMemberSignature = _createMethodSignature( |
| declarationNode, |
| indexedContainer, |
| member, |
| combinedMemberSignatureType as FunctionType, |
| copyLocation: copyLocation, |
| ); |
| break; |
| // Coverage-ignore(suite): Not run. |
| case ProcedureKind.Factory: |
| throw new UnsupportedError( |
| 'Unexpected canonical member kind ${member.kind} for $member', |
| ); |
| } |
| } else if (member is Field) { |
| if (forSetter) { |
| combinedMemberSignature = _createSetterMemberSignature( |
| declarationNode, |
| indexedContainer, |
| member, |
| combinedMemberSignatureType!, |
| isCovariantByClass: member.isCovariantByClass, |
| isCovariantByDeclaration: member.isCovariantByDeclaration, |
| copyLocation: copyLocation, |
| ); |
| } else { |
| combinedMemberSignature = _createGetterMemberSignature( |
| declarationNode, |
| indexedContainer, |
| member, |
| combinedMemberSignatureType!, |
| copyLocation: copyLocation, |
| ); |
| } |
| } else { |
| throw new UnsupportedError( |
| 'Unexpected canonical member $member (${member.runtimeType})', |
| ); |
| } |
| combinedMemberSignatureCovariance!.applyCovariance(combinedMemberSignature); |
| return combinedMemberSignature; |
| } |
| |
| /// Creates a getter member signature for [member] with the given |
| /// [type]. |
| Procedure _createGetterMemberSignature( |
| FileUriNode declarationNode, |
| IndexedContainer? indexedContainer, |
| Member member, |
| DartType type, { |
| required bool copyLocation, |
| }) { |
| Reference? reference = indexedContainer?.lookupGetterReference(member.name); |
| |
| Uri fileUri; |
| int startFileOffset; |
| int fileOffset; |
| if (copyLocation) { |
| // Coverage-ignore-block(suite): Not run. |
| fileUri = member.fileUri; |
| startFileOffset = member is Procedure |
| ? member.fileStartOffset |
| : member.fileOffset; |
| fileOffset = member.fileOffset; |
| } else { |
| fileUri = declarationNode.fileUri; |
| fileOffset = startFileOffset = declarationNode.fileOffset; |
| } |
| return new Procedure( |
| member.name, |
| ProcedureKind.Getter, |
| new FunctionNode(null, returnType: type), |
| isAbstract: true, |
| fileUri: fileUri, |
| reference: reference, |
| isSynthetic: true, |
| stubKind: ProcedureStubKind.MemberSignature, |
| stubTarget: member.memberSignatureOrigin ?? member, |
| ) |
| ..fileStartOffset = startFileOffset |
| ..fileOffset = fileOffset |
| ..parent = declarationNode; |
| } |
| |
| /// Creates a setter member signature for [member] with the given |
| /// [type]. The flags of parameter is set according to |
| /// [isCovariantByDeclaration] and [isCovariantByClass] and the name of the |
| /// [parameter] is used, if provided. |
| Procedure _createSetterMemberSignature( |
| FileUriNode declarationNode, |
| IndexedContainer? indexedContainer, |
| Member member, |
| DartType type, { |
| required bool isCovariantByDeclaration, |
| required bool isCovariantByClass, |
| VariableDeclaration? parameter, |
| required bool copyLocation, |
| }) { |
| Reference? reference = indexedContainer?.lookupSetterReference(member.name); |
| Uri fileUri; |
| int startFileOffset; |
| int fileOffset; |
| if (copyLocation) { |
| // Coverage-ignore-block(suite): Not run. |
| fileUri = member.fileUri; |
| startFileOffset = member is Procedure |
| ? member.fileStartOffset |
| : member.fileOffset; |
| fileOffset = member.fileOffset; |
| } else { |
| fileUri = declarationNode.fileUri; |
| fileOffset = startFileOffset = declarationNode.fileOffset; |
| } |
| return new Procedure( |
| member.name, |
| ProcedureKind.Setter, |
| new FunctionNode( |
| null, |
| returnType: const VoidType(), |
| positionalParameters: [ |
| new VariableDeclaration( |
| parameter?.name ?? 'value', |
| type: type, |
| isCovariantByDeclaration: isCovariantByDeclaration, |
| ) |
| ..isCovariantByClass = isCovariantByClass |
| ..fileOffset = copyLocation |
| ? |
| // Coverage-ignore(suite): Not run. |
| parameter?.fileOffset ?? fileOffset |
| : fileOffset, |
| ], |
| ), |
| isAbstract: true, |
| fileUri: fileUri, |
| reference: reference, |
| isSynthetic: true, |
| stubKind: ProcedureStubKind.MemberSignature, |
| stubTarget: member.memberSignatureOrigin ?? member, |
| ) |
| ..fileStartOffset = startFileOffset |
| ..fileOffset = fileOffset |
| ..parent = declarationNode; |
| } |
| |
| Procedure _createMethodSignature( |
| FileUriNode declarationNode, |
| IndexedContainer? indexedContainer, |
| Procedure procedure, |
| FunctionType functionType, { |
| required bool copyLocation, |
| }) { |
| Reference? reference = indexedContainer?.lookupGetterReference( |
| procedure.name, |
| ); |
| Uri fileUri; |
| int startFileOffset; |
| int fileOffset; |
| if (copyLocation) { |
| // Coverage-ignore-block(suite): Not run. |
| fileUri = procedure.fileUri; |
| startFileOffset = procedure.fileStartOffset; |
| fileOffset = procedure.fileOffset; |
| } else { |
| fileUri = declarationNode.fileUri; |
| fileOffset = startFileOffset = declarationNode.fileOffset; |
| } |
| FunctionNode function = procedure.function; |
| List<VariableDeclaration> positionalParameters = []; |
| FreshTypeParametersFromStructuralParameters freshTypeParameters = |
| getFreshTypeParametersFromStructuralParameters( |
| functionType.typeParameters, |
| ); |
| CloneVisitorNotMembers cloner = new CloneVisitorNotMembers(); |
| for (int i = 0; i < function.positionalParameters.length; i++) { |
| VariableDeclaration parameter = function.positionalParameters[i]; |
| DartType parameterType = freshTypeParameters.substitute( |
| functionType.positionalParameters[i], |
| ); |
| positionalParameters.add( |
| new VariableDeclaration( |
| parameter.name, |
| type: parameterType, |
| isCovariantByDeclaration: parameter.isCovariantByDeclaration, |
| initializer: cloner.cloneOptional(parameter.initializer), |
| ) |
| ..hasDeclaredInitializer = parameter.hasDeclaredInitializer |
| ..isCovariantByClass = parameter.isCovariantByClass |
| ..fileOffset = copyLocation |
| ? |
| // Coverage-ignore(suite): Not run. |
| parameter.fileOffset |
| : fileOffset, |
| ); |
| } |
| List<VariableDeclaration> namedParameters = []; |
| int namedParameterCount = function.namedParameters.length; |
| if (namedParameterCount == 1) { |
| NamedType namedType = functionType.namedParameters.first; |
| VariableDeclaration parameter = function.namedParameters.first; |
| namedParameters.add( |
| new VariableDeclaration( |
| parameter.name, |
| type: freshTypeParameters.substitute(namedType.type), |
| isRequired: namedType.isRequired, |
| isCovariantByDeclaration: parameter.isCovariantByDeclaration, |
| initializer: cloner.cloneOptional(parameter.initializer), |
| ) |
| ..hasDeclaredInitializer = parameter.hasDeclaredInitializer |
| ..isCovariantByClass = parameter.isCovariantByClass |
| ..fileOffset = copyLocation |
| ? |
| // Coverage-ignore(suite): Not run. |
| parameter.fileOffset |
| : fileOffset, |
| ); |
| } else if (namedParameterCount > 1) { |
| Map<String, NamedType> namedTypes = {}; |
| for (NamedType namedType in functionType.namedParameters) { |
| namedTypes[namedType.name] = namedType; |
| } |
| for (int i = 0; i < namedParameterCount; i++) { |
| VariableDeclaration parameter = function.namedParameters[i]; |
| NamedType namedParameterType = namedTypes[parameter.name]!; |
| namedParameters.add( |
| new VariableDeclaration( |
| parameter.name, |
| type: freshTypeParameters.substitute(namedParameterType.type), |
| isRequired: namedParameterType.isRequired, |
| isCovariantByDeclaration: parameter.isCovariantByDeclaration, |
| initializer: cloner.cloneOptional(parameter.initializer), |
| ) |
| ..hasDeclaredInitializer = parameter.hasDeclaredInitializer |
| ..isCovariantByClass = parameter.isCovariantByClass |
| ..fileOffset = copyLocation |
| ? |
| // Coverage-ignore(suite): Not run. |
| parameter.fileOffset |
| : fileOffset, |
| ); |
| } |
| } |
| return new Procedure( |
| procedure.name, |
| procedure.kind, |
| new FunctionNode( |
| null, |
| typeParameters: freshTypeParameters.freshTypeParameters, |
| returnType: freshTypeParameters.substitute(functionType.returnType), |
| positionalParameters: positionalParameters, |
| namedParameters: namedParameters, |
| requiredParameterCount: function.requiredParameterCount, |
| ), |
| isAbstract: true, |
| fileUri: fileUri, |
| reference: reference, |
| isSynthetic: true, |
| stubKind: ProcedureStubKind.MemberSignature, |
| stubTarget: procedure.memberSignatureOrigin ?? procedure, |
| ) |
| ..fileStartOffset = startFileOffset |
| ..fileOffset = fileOffset |
| ..parent = declarationNode; |
| } |
| |
| DartType _computeMemberType(Member member) { |
| DartType type; |
| if (member is Procedure) { |
| if (member.isGetter) { |
| type = member.getterType; |
| } else if (member.isSetter) { |
| type = member.setterType; |
| } else { |
| // TODO(johnniwinther): Why do we need the specific nullability here? |
| type = member.getterType.withDeclaredNullability( |
| declarationBuilder.libraryBuilder.library.nonNullable, |
| ); |
| } |
| } else if (member is Field) { |
| type = member.type; |
| } else { |
| unhandled( |
| "${member.runtimeType}", |
| "$member", |
| declarationBuilder.fileOffset, |
| declarationBuilder.fileUri, |
| ); |
| } |
| if (member.enclosingTypeDeclaration!.typeParameters.isEmpty) { |
| return type; |
| } |
| TypeDeclarationType instance = hierarchy.getTypeAsInstanceOf( |
| thisType, |
| member.enclosingTypeDeclaration!, |
| )!; |
| return Substitution.fromTypeDeclarationType(instance).substituteType(type); |
| } |
| |
| bool _isMoreSpecific(DartType a, DartType b, bool forSetter) { |
| if (forSetter) { |
| return _types.isSubtypeOf(b, a); |
| } else { |
| return _types.isSubtypeOf(a, b); |
| } |
| } |
| } |
| |
| class CombinedClassMemberSignature extends CombinedMemberSignatureBase { |
| final ClassBuilder classBuilder; |
| |
| /// Cache for the this type of [classBuilder]. |
| InterfaceType? _thisType; |
| |
| /// Creates a [CombinedClassMemberSignature] whose canonical member is already |
| /// defined. |
| CombinedClassMemberSignature.internal( |
| ClassMembersBuilder membersBuilder, |
| this.classBuilder, |
| int? canonicalMemberIndex, |
| List<ClassMember> members, { |
| required bool forSetter, |
| }) : super.internal( |
| membersBuilder, |
| canonicalMemberIndex, |
| members, |
| forSetter: forSetter, |
| ); |
| |
| /// Creates a [CombinedClassMemberSignature] for [members] inherited into |
| /// [classBuilder]. |
| /// |
| /// If [forSetter] is `true`, contravariance of the setter types is used to |
| /// compute the most specific member type. Otherwise covariance of the getter |
| /// types or function types is used. |
| CombinedClassMemberSignature( |
| ClassMembersBuilder membersBuilder, |
| this.classBuilder, |
| List<ClassMember> members, { |
| required bool forSetter, |
| }) : super(membersBuilder, members, forSetter: forSetter); |
| |
| @override |
| DeclarationBuilder get declarationBuilder => classBuilder; |
| |
| /// The this type of [classBuilder]. |
| @override |
| InterfaceType get thisType { |
| return _thisType ??= _coreTypes.thisInterfaceType( |
| classBuilder.cls, |
| Nullability.nonNullable, |
| ); |
| } |
| |
| /// Returns `true` if the canonical member is declared in |
| /// [declarationBuilder]. |
| @override |
| bool get isCanonicalMemberDeclared { |
| return _canonicalMemberIndex != null && |
| _getMember(_canonicalMemberIndex!).enclosingClass == classBuilder.cls; |
| } |
| } |
| |
| class CombinedExtensionTypeMemberSignature extends CombinedMemberSignatureBase { |
| final ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder; |
| |
| /// Cache for the this type of [extensionTypeDeclarationBuilder]. |
| ExtensionType? _thisType; |
| |
| /// Creates a [CombinedClassMemberSignature] for [members] inherited into |
| /// [extensionTypeDeclarationBuilder]. |
| /// |
| /// If [forSetter] is `true`, contravariance of the setter types is used to |
| /// compute the most specific member type. Otherwise covariance of the getter |
| /// types or function types is used. |
| CombinedExtensionTypeMemberSignature( |
| ClassMembersBuilder membersBuilder, |
| this.extensionTypeDeclarationBuilder, |
| List<ClassMember> members, { |
| required bool forSetter, |
| }) : super(membersBuilder, members, forSetter: forSetter); |
| |
| @override |
| DeclarationBuilder get declarationBuilder => extensionTypeDeclarationBuilder; |
| |
| /// The this type of [extensionTypeDeclarationBuilder]. |
| @override |
| ExtensionType get thisType { |
| return _thisType ??= _coreTypes.thisExtensionType( |
| extensionTypeDeclarationBuilder.extensionTypeDeclaration, |
| Nullability.nonNullable, |
| ); |
| } |
| |
| @override |
| bool get isCanonicalMemberDeclared => false; |
| } |