Skip to content

Sema: Simplify logic for building extension generic signature #41820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 31 additions & 87 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,23 +468,19 @@ 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<Requirement> &sameTypeReqs,
bool &mustInferRequirements) {
/// Collect additional requirements into \p sameTypeReqs.
static void collectAdditionalExtensionRequirements(
Type type, SmallVectorImpl<Requirement> &sameTypeReqs) {
if (type->is<ErrorType>())
return type;
return;

// Find the nominal type declaration and its parent type.
if (type->is<ProtocolCompositionType>())
type = type->getCanonicalType();

// 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<ParameterizedProtocolType>()) {
auto *protoTy = paramProtoTy->getBaseType();
type = protoTy;
Expand All @@ -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.
Expand All @@ -516,59 +506,26 @@ static Type formExtensionInterfaceType(
nominal = type->getNominalOrBoundGenericNominal();
}

// Form the result.
Type resultType;
SmallVector<Type, 2> genericArgs;
if (!nominal->isGeneric() || isa<ProtocolDecl>(nominal)) {
resultType = NominalType::get(nominal, parentType,
nominal->getASTContext());
} else if (genericParams) {
auto currentBoundType = type->getAs<BoundGenericType>();

// 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<BoundGenericType>()) {
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<unsigned>(-1);

auto sig = nominal->getGenericSignatureOfContext();
if (!sig) return static_cast<unsigned>(-1);

return sig.getGenericParams().back()->getDepth();
}

GenericSignature
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -650,10 +607,12 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
return GC->getParentForLookup()->getGenericSignatureOfContext();
}

auto parentSig = GC->getParentForLookup()->getGenericSignatureOfContext();
GenericSignature parentSig;
SmallVector<TypeLoc, 2> inferenceSources;
SmallVector<Requirement, 2> sameTypeReqs;
if (auto VD = dyn_cast_or_null<ValueDecl>(GC->getAsDecl())) {
parentSig = GC->getParentForLookup()->getGenericSignatureOfContext();

auto func = dyn_cast<AbstractFunctionDecl>(VD);
auto subscr = dyn_cast<SubscriptDecl>(VD);

Expand Down Expand Up @@ -708,38 +667,23 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
}
}
} else if (auto *ext = dyn_cast<ExtensionDecl>(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,
Expand Down
3 changes: 3 additions & 0 deletions test/Generics/conditional_conformances.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct RedundantSame<T: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSame
// CHECK-NEXT: (normal_conformance type=RedundantSame<T> protocol=P2)
extension RedundantSame: P2 where T: P1 {}
// expected-warning@-1 {{redundant conformance constraint 'T' : 'P1'}}

struct RedundantSuper<T: P4> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSuper
Expand Down Expand Up @@ -334,6 +335,8 @@ struct RedundancyOrderDependenceGood<T: P1, U> {}
// CHECK-NEXT: (normal_conformance type=RedundancyOrderDependenceGood<T, U> 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<T, U: P1> {}
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad
// CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad
Expand Down
13 changes: 9 additions & 4 deletions test/SourceKit/DocSupport/doc_swift_module.swift.response
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -2557,7 +2557,7 @@ func shouldPrintAnyAsKeyword(x x: Any)
],
key.offset: 1574,
key.length: 63,
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:4cake4ProtP\">Prot</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:4cake4ProtPAASi7ElementRtzrlE4Selfxmfp\">Self</ref.generic_type_param>.<ref.associatedtype usr=\"s:4cake4ProtP7ElementQa\">Element</ref.associatedtype> == <ref.struct usr=\"s:Si\">Int</ref.struct></decl.generic_type_requirement></decl.extension.protocol>",
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:4cake4ProtP\">Prot</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:4cake4ProtP4Selfxmfp\">Self</ref.generic_type_param>.<ref.associatedtype usr=\"s:4cake4ProtP7ElementQa\">Element</ref.associatedtype> == <ref.struct usr=\"s:Si\">Int</ref.struct></decl.generic_type_requirement></decl.extension.protocol>",
key.extends: {
key.kind: source.lang.swift.ref.protocol,
key.name: "Prot",
Expand Down Expand Up @@ -2758,14 +2758,19 @@ 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"
}
],
key.offset: 2022,
key.length: 80,
key.fully_annotated_decl: "<syntaxtype.keyword>extension</syntaxtype.keyword> <ref.struct usr=\"s:4cake2S3V\">S3</ref.struct> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:4cake2S3VA2A2P6RzrlE7Wrappedxmfp\">Wrapped</ref.generic_type_param> : <ref.protocol usr=\"s:4cake2P6P\">P6</ref.protocol></decl.generic_type_requirement>",
key.fully_annotated_decl: "<syntaxtype.keyword>extension</syntaxtype.keyword> <ref.struct usr=\"s:4cake2S3V\">S3</ref.struct> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:4cake2S3V7Wrappedxmfp\">Wrapped</ref.generic_type_param> : <ref.protocol usr=\"s:4cake2P6P\">P6</ref.protocol></decl.generic_type_requirement>",
key.extends: {
key.kind: source.lang.swift.ref.struct,
key.name: "S3",
Expand Down
16 changes: 12 additions & 4 deletions test/SourceKit/DocSupport/doc_swift_module1.swift.response
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -1038,7 +1038,7 @@ extension Dictionary.Keys where Key : cake1.P1 {
],
key.offset: 651,
key.length: 64,
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:5cake12P2P\">P2</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:5cake12P2PA2A2P3RzrlE4Selfxmfp\">Self</ref.generic_type_param> : <ref.protocol usr=\"s:5cake12P3P\">P3</ref.protocol></decl.generic_type_requirement></decl.extension.protocol>",
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:5cake12P2P\">P2</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:5cake12P2P4Selfxmfp\">Self</ref.generic_type_param> : <ref.protocol usr=\"s:5cake12P3P\">P3</ref.protocol></decl.generic_type_requirement></decl.extension.protocol>",
key.extends: {
key.kind: source.lang.swift.ref.protocol,
key.name: "P2",
Expand Down Expand Up @@ -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"
Expand All @@ -1120,7 +1128,7 @@ extension Dictionary.Keys where Key : cake1.P1 {
],
key.offset: 804,
key.length: 66,
key.fully_annotated_decl: "<decl.extension.struct><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.struct usr=\"s:SD\">Dictionary</ref.struct>.<ref.struct usr=\"s:SD4KeysV\">Keys</ref.struct></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:SD4KeysV5cake1AC2P1RzrlE3Keyxmfp\">Key</ref.generic_type_param> : <ref.protocol usr=\"s:5cake12P1P\">P1</ref.protocol></decl.generic_type_requirement></decl.extension.struct>",
key.fully_annotated_decl: "<decl.extension.struct><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.struct usr=\"s:SD\">Dictionary</ref.struct>.<ref.struct usr=\"s:SD4KeysV\">Keys</ref.struct></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:SD3Keyxmfp\">Key</ref.generic_type_param> : <ref.protocol usr=\"s:5cake12P1P\">P1</ref.protocol></decl.generic_type_requirement></decl.extension.struct>",
key.extends: {
key.kind: source.lang.swift.ref.struct,
key.name: "Keys",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -470,14 +470,19 @@ 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"
}
],
key.offset: 112,
key.length: 87,
key.fully_annotated_decl: "<decl.extension.class><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.class usr=\"s:27module_with_class_extension1CC\">C</ref.class></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:27module_with_class_extension1CCA2A1DCRbzlE1Txmfp\">T</ref.generic_type_param> : <ref.class usr=\"s:27module_with_class_extension1DC\">D</ref.class></decl.generic_type_requirement></decl.extension.class>",
key.fully_annotated_decl: "<decl.extension.class><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.class usr=\"s:27module_with_class_extension1CC\">C</ref.class></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:27module_with_class_extension1CC1Txmfp\">T</ref.generic_type_param> : <ref.class usr=\"s:27module_with_class_extension1DC\">D</ref.class></decl.generic_type_requirement></decl.extension.class>",
key.extends: {
key.kind: source.lang.swift.ref.class,
key.name: "C",
Expand Down Expand Up @@ -630,7 +635,7 @@ extension P8 where Self.T : module_with_class_extension.E {
],
key.offset: 461,
key.length: 77,
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:27module_with_class_extension2P8P\">P8</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:27module_with_class_extension2P8PA2A1DC1TRczrlE4Selfxmfp\">Self</ref.generic_type_param>.<ref.associatedtype usr=\"s:27module_with_class_extension2P8P1TQa\">T</ref.associatedtype> : <ref.class usr=\"s:27module_with_class_extension1DC\">D</ref.class></decl.generic_type_requirement></decl.extension.protocol>",
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:27module_with_class_extension2P8P\">P8</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:27module_with_class_extension2P8P4Selfxmfp\">Self</ref.generic_type_param>.<ref.associatedtype usr=\"s:27module_with_class_extension2P8P1TQa\">T</ref.associatedtype> : <ref.class usr=\"s:27module_with_class_extension1DC\">D</ref.class></decl.generic_type_requirement></decl.extension.protocol>",
key.extends: {
key.kind: source.lang.swift.ref.protocol,
key.name: "P8",
Expand All @@ -656,7 +661,7 @@ extension P8 where Self.T : module_with_class_extension.E {
],
key.offset: 540,
key.length: 77,
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:27module_with_class_extension2P8P\">P8</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:27module_with_class_extension2P8PA2A1EC1TRczrlE4Selfxmfp\">Self</ref.generic_type_param>.<ref.associatedtype usr=\"s:27module_with_class_extension2P8P1TQa\">T</ref.associatedtype> : <ref.class usr=\"s:27module_with_class_extension1EC\">E</ref.class></decl.generic_type_requirement></decl.extension.protocol>",
key.fully_annotated_decl: "<decl.extension.protocol><syntaxtype.keyword>extension</syntaxtype.keyword> <decl.name><ref.protocol usr=\"s:27module_with_class_extension2P8P\">P8</ref.protocol></decl.name> <syntaxtype.keyword>where</syntaxtype.keyword> <decl.generic_type_requirement><ref.generic_type_param usr=\"s:27module_with_class_extension2P8P4Selfxmfp\">Self</ref.generic_type_param>.<ref.associatedtype usr=\"s:27module_with_class_extension2P8P1TQa\">T</ref.associatedtype> : <ref.class usr=\"s:27module_with_class_extension1EC\">E</ref.class></decl.generic_type_requirement></decl.extension.protocol>",
key.extends: {
key.kind: source.lang.swift.ref.protocol,
key.name: "P8",
Expand Down
Loading