diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 0b3ab22a79bd1..07ec072ff3c5f 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -468,15 +468,11 @@ void TypeChecker::checkReferencedGenericParams(GenericContext *dc) { /// Generic types /// -/// Form the interface type of an extension from the raw type and the -/// extension's list of generic parameters. -static Type formExtensionInterfaceType( - ExtensionDecl *ext, Type type, - const GenericParamList *genericParams, - SmallVectorImpl &sameTypeReqs, - bool &mustInferRequirements) { +/// Collect additional requirements into \p sameTypeReqs. +static void collectAdditionalExtensionRequirements( + Type type, SmallVectorImpl &sameTypeReqs) { if (type->is()) - return type; + return; // Find the nominal type declaration and its parent type. if (type->is()) @@ -484,7 +480,7 @@ static Type formExtensionInterfaceType( // A parameterized protocol type is not a nominal. Unwrap it to get // the underlying nominal, and record a same-type requirement for - // the primary associated type. + // the primary associated types. if (auto *paramProtoTy = type->getAs()) { auto *protoTy = paramProtoTy->getBaseType(); type = protoTy; @@ -497,15 +493,9 @@ static Type formExtensionInterfaceType( Type parentType = type->getNominalParent(); GenericTypeDecl *genericDecl = type->getAnyGeneric(); - // Reconstruct the parent, if there is one. + // Visit the parent type, if there is one. if (parentType) { - // Build the nested extension type. - auto parentGenericParams = genericDecl->getGenericParams() - ? genericParams->getOuterParameters() - : genericParams; - parentType = - formExtensionInterfaceType(ext, parentType, parentGenericParams, - sameTypeReqs, mustInferRequirements); + collectAdditionalExtensionRequirements(parentType, sameTypeReqs); } // Find the nominal type. @@ -516,59 +506,26 @@ static Type formExtensionInterfaceType( nominal = type->getNominalOrBoundGenericNominal(); } - // Form the result. - Type resultType; - SmallVector genericArgs; - if (!nominal->isGeneric() || isa(nominal)) { - resultType = NominalType::get(nominal, parentType, - nominal->getASTContext()); - } else if (genericParams) { - auto currentBoundType = type->getAs(); - - // Form the bound generic type with the type parameters provided. - unsigned gpIndex = 0; - for (auto gp : *genericParams) { - SWIFT_DEFER { ++gpIndex; }; - + // If we have a bound generic type, add same-type requirements for each of + // its generic arguments. + if (auto currentBoundType = type->getAs()) { + auto *genericParams = currentBoundType->getDecl()->getGenericParams(); + for (unsigned gpIndex : indices(genericParams->getParams())) { + auto *gp = genericParams->getParams()[gpIndex]; auto gpType = gp->getDeclaredInterfaceType(); - genericArgs.push_back(gpType); - if (currentBoundType) { - sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, - currentBoundType->getGenericArgs()[gpIndex]); - } + sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, + currentBoundType->getGenericArgs()[gpIndex]); } - - resultType = BoundGenericType::get(nominal, parentType, genericArgs); } - // If we have a typealias, try to form type sugar. + // If we have a passthrough typealias, add the requirements from its + // generic signature. if (typealias && TypeChecker::isPassThroughTypealias( typealias, typealias->getUnderlyingType(), nominal)) { - auto typealiasSig = typealias->getGenericSignature(); - SubstitutionMap subMap; - if (typealiasSig) { - subMap = typealiasSig->getIdentitySubstitutionMap(); - - mustInferRequirements = true; - } - - resultType = TypeAliasType::get(typealias, parentType, subMap, resultType); + for (auto req : typealias->getGenericSignature().getRequirements()) + sameTypeReqs.push_back(req); } - - - return resultType; -} - -/// Retrieve the generic parameter depth of the extended type. -static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { - auto nominal = ext->getSelfNominalTypeDecl(); - if (!nominal) return static_cast(-1); - - auto sig = nominal->getGenericSignatureOfContext(); - if (!sig) return static_cast(-1); - - return sig.getGenericParams().back()->getDepth(); } GenericSignature @@ -605,7 +562,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, } bool allowConcreteGenericParams = false; - const auto *genericParams = GC->getGenericParams(); + auto *genericParams = GC->getGenericParams(); const auto *where = GC->getTrailingWhereClause(); if (genericParams) { @@ -650,10 +607,12 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, return GC->getParentForLookup()->getGenericSignatureOfContext(); } - auto parentSig = GC->getParentForLookup()->getGenericSignatureOfContext(); + GenericSignature parentSig; SmallVector inferenceSources; SmallVector sameTypeReqs; if (auto VD = dyn_cast_or_null(GC->getAsDecl())) { + parentSig = GC->getParentForLookup()->getGenericSignatureOfContext(); + auto func = dyn_cast(VD); auto subscr = dyn_cast(VD); @@ -708,38 +667,23 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, } } } else if (auto *ext = dyn_cast(GC)) { - // Form the interface type of the extension so we can use it as an inference - // source. - // - // FIXME: Push this into the "get interface type" request. - bool mustInferRequirements = false; - Type extInterfaceType = - formExtensionInterfaceType(ext, ext->getExtendedType(), - genericParams, sameTypeReqs, - mustInferRequirements); - - auto cannotReuseNominalSignature = [&]() -> bool { - const auto finalDepth = genericParams->getParams().back()->getDepth(); - return mustInferRequirements - || !sameTypeReqs.empty() - || ext->getTrailingWhereClause() - || (getExtendedTypeGenericDepth(ext) != finalDepth); - }; + parentSig = ext->getExtendedNominal()->getGenericSignatureOfContext(); + genericParams = nullptr; + + collectAdditionalExtensionRequirements(ext->getExtendedType(), sameTypeReqs); - // Re-use the signature of the type being extended by default. - if (!cannotReuseNominalSignature()) { - return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); + // Re-use the signature of the type being extended by default. + if (sameTypeReqs.empty() && !ext->getTrailingWhereClause()) { + return parentSig; } // Allow parameters to be equated with concrete types. allowConcreteGenericParams = true; - - inferenceSources.emplace_back(nullptr, extInterfaceType); } auto request = InferredGenericSignatureRequest{ parentSig.getPointer(), - GC->getGenericParams(), WhereClauseOwner(GC), + genericParams, WhereClauseOwner(GC), sameTypeReqs, inferenceSources, allowConcreteGenericParams}; auto sig = evaluateOrDefault(ctx.evaluator, request, diff --git a/test/Generics/conditional_conformances.swift b/test/Generics/conditional_conformances.swift index 196065c308cc4..dc7fe35f96866 100644 --- a/test/Generics/conditional_conformances.swift +++ b/test/Generics/conditional_conformances.swift @@ -49,6 +49,7 @@ struct RedundantSame {} // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSame // CHECK-NEXT: (normal_conformance type=RedundantSame protocol=P2) extension RedundantSame: P2 where T: P1 {} +// expected-warning@-1 {{redundant conformance constraint 'T' : 'P1'}} struct RedundantSuper {} // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSuper @@ -334,6 +335,8 @@ struct RedundancyOrderDependenceGood {} // CHECK-NEXT: (normal_conformance type=RedundancyOrderDependenceGood protocol=P2 // CHECK-NEXT: same_type: T U) extension RedundancyOrderDependenceGood: P2 where U: P1, T == U {} +// expected-warning@-1 {{redundant conformance constraint 'U' : 'P1'}} + struct RedundancyOrderDependenceBad {} // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad diff --git a/test/SourceKit/DocSupport/doc_swift_module.swift.response b/test/SourceKit/DocSupport/doc_swift_module.swift.response index f1fc0a593b5d3..15e86fbbbff16 100644 --- a/test/SourceKit/DocSupport/doc_swift_module.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module.swift.response @@ -1301,7 +1301,7 @@ func shouldPrintAnyAsKeyword(x x: Any) { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:4cake4ProtPAASi7ElementRtzrlE4Selfxmfp", + key.usr: "s:4cake4ProtP4Selfxmfp", key.offset: 1595, key.length: 4 }, @@ -1649,7 +1649,7 @@ func shouldPrintAnyAsKeyword(x x: Any) { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Wrapped", - key.usr: "s:4cake2S3VA2A2P6RzrlE7Wrappedxmfp", + key.usr: "s:4cake2S3V7Wrappedxmfp", key.offset: 2041, key.length: 7 }, @@ -2557,7 +2557,7 @@ func shouldPrintAnyAsKeyword(x x: Any) ], key.offset: 1574, key.length: 63, - key.fully_annotated_decl: "extension Prot where Self.Element == Int", + key.fully_annotated_decl: "extension Prot where Self.Element == Int", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "Prot", @@ -2758,6 +2758,11 @@ func shouldPrintAnyAsKeyword(x x: Any) }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "Wrapped" + } + ], key.generic_requirements: [ { key.description: "Wrapped : P6" @@ -2765,7 +2770,7 @@ func shouldPrintAnyAsKeyword(x x: Any) ], key.offset: 2022, key.length: 80, - key.fully_annotated_decl: "extension S3 where Wrapped : P6", + key.fully_annotated_decl: "extension S3 where Wrapped : P6", key.extends: { key.kind: source.lang.swift.ref.struct, key.name: "S3", diff --git a/test/SourceKit/DocSupport/doc_swift_module1.swift.response b/test/SourceKit/DocSupport/doc_swift_module1.swift.response index 662df987b140b..1cae78fc9741d 100644 --- a/test/SourceKit/DocSupport/doc_swift_module1.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module1.swift.response @@ -569,7 +569,7 @@ extension Dictionary.Keys where Key : cake1.P1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:5cake12P2PA2A2P3RzrlE4Selfxmfp", + key.usr: "s:5cake12P2P4Selfxmfp", key.offset: 670, key.length: 4 }, @@ -671,7 +671,7 @@ extension Dictionary.Keys where Key : cake1.P1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Key", - key.usr: "s:SD4KeysV5cake1AC2P1RzrlE3Keyxmfp", + key.usr: "s:SD3Keyxmfp", key.offset: 836, key.length: 3 }, @@ -1038,7 +1038,7 @@ extension Dictionary.Keys where Key : cake1.P1 { ], key.offset: 651, key.length: 64, - key.fully_annotated_decl: "extension P2 where Self : P3", + key.fully_annotated_decl: "extension P2 where Self : P3", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "P2", @@ -1110,6 +1110,14 @@ extension Dictionary.Keys where Key : cake1.P1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "Key" + }, + { + key.name: "Value" + } + ], key.generic_requirements: [ { key.description: "Key : Hashable" @@ -1120,7 +1128,7 @@ extension Dictionary.Keys where Key : cake1.P1 { ], key.offset: 804, key.length: 66, - key.fully_annotated_decl: "extension Dictionary.Keys where Key : P1", + key.fully_annotated_decl: "extension Dictionary.Keys where Key : P1", key.extends: { key.kind: source.lang.swift.ref.struct, key.name: "Keys", diff --git a/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response b/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response index 7af1a0c5b29bb..87befec96d775 100644 --- a/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response @@ -129,7 +129,7 @@ extension P8 where Self.T : module_with_class_extension.E { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:27module_with_class_extension1CCA2A1DCRbzlE1Txmfp", + key.usr: "s:27module_with_class_extension1CC1Txmfp", key.offset: 130, key.length: 1 }, @@ -344,7 +344,7 @@ extension P8 where Self.T : module_with_class_extension.E { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:27module_with_class_extension2P8PA2A1DC1TRczrlE4Selfxmfp", + key.usr: "s:27module_with_class_extension2P8P4Selfxmfp", key.offset: 480, key.length: 4 }, @@ -397,7 +397,7 @@ extension P8 where Self.T : module_with_class_extension.E { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:27module_with_class_extension2P8PA2A1EC1TRczrlE4Selfxmfp", + key.usr: "s:27module_with_class_extension2P8P4Selfxmfp", key.offset: 559, key.length: 4 }, @@ -470,6 +470,11 @@ extension P8 where Self.T : module_with_class_extension.E { }, { key.kind: source.lang.swift.decl.extension.class, + key.generic_params: [ + { + key.name: "T" + } + ], key.generic_requirements: [ { key.description: "T : D" @@ -477,7 +482,7 @@ extension P8 where Self.T : module_with_class_extension.E { ], key.offset: 112, key.length: 87, - key.fully_annotated_decl: "extension C where T : D", + key.fully_annotated_decl: "extension C where T : D", key.extends: { key.kind: source.lang.swift.ref.class, key.name: "C", @@ -630,7 +635,7 @@ extension P8 where Self.T : module_with_class_extension.E { ], key.offset: 461, key.length: 77, - key.fully_annotated_decl: "extension P8 where Self.T : D", + key.fully_annotated_decl: "extension P8 where Self.T : D", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "P8", @@ -656,7 +661,7 @@ extension P8 where Self.T : module_with_class_extension.E { ], key.offset: 540, key.length: 77, - key.fully_annotated_decl: "extension P8 where Self.T : E", + key.fully_annotated_decl: "extension P8 where Self.T : E", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "P8", diff --git a/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response b/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response index 69b177d042cbb..f9293f870ddd7 100644 --- a/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response +++ b/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response @@ -219,7 +219,7 @@ protocol Other1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:16UnderscoredProto1AVAASSRszlE1Txmfp", + key.usr: "s:16UnderscoredProto1AV1Txmfp", key.offset: 227, key.length: 1 }, @@ -849,7 +849,7 @@ protocol Other1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:16UnderscoredProto1DVAASQRzrlE1Txmfp", + key.usr: "s:16UnderscoredProto1DV1Txmfp", key.offset: 1411, key.length: 1 }, @@ -911,7 +911,7 @@ protocol Other1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:16UnderscoredProto1DVAASQRzrlE1Txmfp", + key.usr: "s:16UnderscoredProto1DV1Txmfp", key.offset: 1484, key.length: 1 }, @@ -1050,6 +1050,11 @@ protocol Other1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "T" + } + ], key.generic_requirements: [ { key.description: "T == String" @@ -1057,7 +1062,7 @@ protocol Other1 { ], key.offset: 209, key.length: 185, - key.fully_annotated_decl: "extension A : _UnderscoredProto2 where T == String", + key.fully_annotated_decl: "extension A : _UnderscoredProto2 where T == String", key.conforms: [ { key.kind: source.lang.swift.ref.protocol, @@ -1520,6 +1525,14 @@ protocol Other1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "T" + }, + { + key.name: "U" + } + ], key.generic_requirements: [ { key.description: "T : Equatable" @@ -1527,7 +1540,7 @@ protocol Other1 { ], key.offset: 1393, key.length: 59, - key.fully_annotated_decl: "extension D : _SomeProto where T : Equatable", + key.fully_annotated_decl: "extension D : _SomeProto where T : Equatable", key.conforms: [ { key.kind: source.lang.swift.ref.protocol, @@ -1560,6 +1573,14 @@ protocol Other1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "T" + }, + { + key.name: "U" + } + ], key.generic_requirements: [ { key.description: "T : Other1" @@ -1570,7 +1591,7 @@ protocol Other1 { ], key.offset: 1454, key.length: 135, - key.fully_annotated_decl: "extension D where T : Other1, T : Equatable", + key.fully_annotated_decl: "extension D where T : Other1, T : Equatable", key.extends: { key.kind: source.lang.swift.ref.struct, key.name: "D",