Merge pull request #17419 from slavapestov/generic-init-inherit-fix
Sema: Use a different strategy for computing derived initializer generic signature
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 2c81d96..7f017f6 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -2048,36 +2048,6 @@
newParams.push_back(newParam);
}
- // Substitution map that maps the generic parameters of the superclass
- // to the generic parameters of the derived class, and the generic
- // parameters of the superclass initializer to the generic parameters
- // of the derived class initializer.
- auto *superclassSig = superclassCtor->getGenericSignature();
- if (superclassSig) {
- unsigned superclassDepth = 0;
- if (auto *genericSig = superclassDecl->getGenericSignature())
- superclassDepth = genericSig->getGenericParams().back()->getDepth() + 1;
-
- subMap = SubstitutionMap::get(
- superclassSig,
- [&](SubstitutableType *type) -> Type {
- auto *gp = cast<GenericTypeParamType>(type);
- if (gp->getDepth() < superclassDepth)
- return Type(gp).subst(subMap);
- return CanGenericTypeParamType::get(
- gp->getDepth() - superclassDepth + depth,
- gp->getIndex(),
- ctx);
- },
- [&](CanType depTy, Type substTy, ProtocolDecl *proto)
- -> Optional<ProtocolConformanceRef> {
- if (auto conf = subMap.lookupConformance(depTy, proto))
- return conf;
-
- return ProtocolConformanceRef(proto);
- });
- }
-
// We don't have to clone the requirements, because they're not
// used for anything.
genericParams = GenericParamList::create(ctx,
@@ -2088,18 +2058,52 @@
SourceLoc());
genericParams->setOuterParameters(classDecl->getGenericParamsOfContext());
+ // Build a generic signature for the derived class initializer.
GenericSignatureBuilder builder(ctx);
builder.addGenericSignature(classDecl->getGenericSignature());
+ // Add the generic parameters.
for (auto *newParam : newParams)
builder.addGenericParameter(newParam);
auto source =
GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
+ auto *superclassSig = superclassCtor->getGenericSignature();
+
+ unsigned superclassDepth = 0;
+ if (auto *genericSig = superclassDecl->getGenericSignature())
+ superclassDepth = genericSig->getGenericParams().back()->getDepth() + 1;
+
+ // We're going to be substituting the requirements of the base class
+ // initializer to form the requirements of the derived class initializer.
+ auto substFn = [&](SubstitutableType *type) -> Type {
+ auto *gp = cast<GenericTypeParamType>(type);
+ if (gp->getDepth() < superclassDepth)
+ return Type(gp).subst(subMap);
+ return CanGenericTypeParamType::get(
+ gp->getDepth() - superclassDepth + depth,
+ gp->getIndex(),
+ ctx);
+ };
+
+ auto lookupConformanceFn =
+ [&](CanType depTy, Type substTy, ProtocolDecl *proto)
+ -> Optional<ProtocolConformanceRef> {
+ if (auto conf = subMap.lookupConformance(depTy, proto))
+ return conf;
+
+ return ProtocolConformanceRef(proto);
+ };
+
for (auto reqt : superclassSig->getRequirements())
- if (auto substReqt = reqt.subst(subMap))
+ if (auto substReqt = reqt.subst(substFn, lookupConformanceFn))
builder.addRequirement(*substReqt, source, nullptr);
+ // Now form the substitution map that will be used to remap parameter
+ // types.
+ subMap = SubstitutionMap::get(superclassSig,
+ substFn, lookupConformanceFn);
+
genericSig = std::move(builder).computeGenericSignature(SourceLoc());
genericEnv = genericSig->createGenericEnvironment();
} else {
diff --git a/test/SILGen/inherit_initializers.swift b/test/SILGen/inherit_initializers.swift
index 731fd44..7daff76 100644
--- a/test/SILGen/inherit_initializers.swift
+++ b/test/SILGen/inherit_initializers.swift
@@ -122,4 +122,6 @@
init<Z>(_: Z) where Z : Q, Z.A == X, Z.B == Y, X == Y {}
}
-class Once<T> : Twice<T, T> {}
\ No newline at end of file
+class Pair<T, U> : Twice<T, U> {}
+
+class Once<T> : Twice<T, T> {}