Skip to content

Commit 4e4976b

Browse files
authored
Merge pull request #17316 from slavapestov/generic-init-inheritance
Fix inheritance of generic initializers
2 parents 92189c6 + 0e91735 commit 4e4976b

File tree

6 files changed

+270
-154
lines changed

6 files changed

+270
-154
lines changed

lib/AST/Type.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,31 +3261,33 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
32613261
assert(ownerNominal == baseTy->getAnyNominal());
32623262

32633263
// Gather all of the substitutions for all levels of generic arguments.
3264-
GenericParamList *curGenericParams = dc->getGenericParamsOfContext();
3265-
if (!curGenericParams)
3264+
auto *genericSig = dc->getGenericSignatureOfContext();
3265+
if (!genericSig)
32663266
return substitutions;
32673267

3268-
while (baseTy && curGenericParams) {
3268+
auto params = genericSig->getGenericParams();
3269+
unsigned n = params.size();
3270+
3271+
while (baseTy && n > 0) {
32693272
// For a bound generic type, gather the generic parameter -> generic
32703273
// argument substitutions.
32713274
if (auto boundGeneric = baseTy->getAs<BoundGenericType>()) {
3272-
auto params = curGenericParams->getParams();
32733275
auto args = boundGeneric->getGenericArgs();
3274-
for (unsigned i = 0, n = args.size(); i != n; ++i) {
3275-
substitutions[params[i]->getDeclaredInterfaceType()->getCanonicalType()
3276+
for (unsigned i = 0, e = args.size(); i < e; ++i) {
3277+
substitutions[params[n - e + i]->getCanonicalType()
32763278
->castTo<GenericTypeParamType>()] = args[i];
32773279
}
32783280

32793281
// Continue looking into the parent.
32803282
baseTy = boundGeneric->getParent();
3281-
curGenericParams = curGenericParams->getOuterParameters();
3283+
n -= args.size();
32823284
continue;
32833285
}
32843286

32853287
// Continue looking into the parent.
32863288
if (auto protocolTy = baseTy->getAs<ProtocolType>()) {
32873289
baseTy = protocolTy->getParent();
3288-
curGenericParams = curGenericParams->getOuterParameters();
3290+
n--;
32893291
continue;
32903292
}
32913293

@@ -3298,19 +3300,16 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
32983300
llvm_unreachable("Bad base type");
32993301
}
33003302

3301-
if (genericEnv) {
3302-
auto *parentDC = dc;
3303-
while (parentDC->isTypeContext())
3304-
parentDC = parentDC->getParent();
3305-
if (auto *outerSig = parentDC->getGenericSignatureOfContext()) {
3306-
for (auto gp : outerSig->getGenericParams()) {
3307-
auto result = substitutions.insert(
3308-
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
3309-
genericEnv->mapTypeIntoContext(gp)});
3310-
assert(result.second);
3311-
(void) result;
3312-
}
3313-
}
3303+
while (n > 0) {
3304+
auto *gp = params[--n];
3305+
auto substTy = (genericEnv
3306+
? genericEnv->mapTypeIntoContext(gp)
3307+
: gp);
3308+
auto result = substitutions.insert(
3309+
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
3310+
substTy});
3311+
assert(result.second);
3312+
(void) result;
33143313
}
33153314

33163315
return substitutions;

lib/Sema/CodeSynthesis.cpp

Lines changed: 121 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Availability.h"
2323
#include "swift/AST/Expr.h"
2424
#include "swift/AST/GenericEnvironment.h"
25+
#include "swift/AST/GenericSignatureBuilder.h"
2526
#include "swift/AST/Initializer.h"
2627
#include "swift/AST/ParameterList.h"
2728
#include "swift/AST/ProtocolConformance.h"
@@ -2011,6 +2012,104 @@ static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) {
20112012
ctor->setStubImplementation(true);
20122013
}
20132014

2015+
static std::tuple<GenericSignature *, GenericEnvironment *,
2016+
GenericParamList *, SubstitutionMap>
2017+
configureGenericDesignatedInitOverride(ASTContext &ctx,
2018+
ClassDecl *classDecl,
2019+
Type superclassTy,
2020+
ConstructorDecl *superclassCtor) {
2021+
auto *superclassDecl = superclassTy->getAnyNominal();
2022+
2023+
auto *moduleDecl = classDecl->getParentModule();
2024+
auto subMap = superclassTy->getContextSubstitutionMap(
2025+
moduleDecl, superclassDecl);
2026+
2027+
GenericSignature *genericSig;
2028+
GenericEnvironment *genericEnv;
2029+
2030+
// Inheriting initializers that have their own generic parameters
2031+
auto *genericParams = superclassCtor->getGenericParams();
2032+
if (genericParams) {
2033+
SmallVector<GenericTypeParamDecl *, 4> newParams;
2034+
2035+
// First, clone the superclass constructor's generic parameter list,
2036+
// but change the depth of the generic parameters to be one greater
2037+
// than the depth of the subclass.
2038+
unsigned depth = 0;
2039+
if (auto *genericSig = classDecl->getGenericSignature())
2040+
depth = genericSig->getGenericParams().back()->getDepth() + 1;
2041+
2042+
for (auto *param : genericParams->getParams()) {
2043+
auto *newParam = new (ctx) GenericTypeParamDecl(classDecl,
2044+
param->getName(),
2045+
SourceLoc(),
2046+
depth,
2047+
param->getIndex());
2048+
newParams.push_back(newParam);
2049+
}
2050+
2051+
// Substitution map that maps the generic parameters of the superclass
2052+
// to the generic parameters of the derived class, and the generic
2053+
// parameters of the superclass initializer to the generic parameters
2054+
// of the derived class initializer.
2055+
auto *superclassSig = superclassCtor->getGenericSignature();
2056+
if (superclassSig) {
2057+
unsigned superclassDepth = 0;
2058+
if (auto *genericSig = superclassDecl->getGenericSignature())
2059+
superclassDepth = genericSig->getGenericParams().back()->getDepth() + 1;
2060+
2061+
subMap = SubstitutionMap::get(
2062+
superclassSig,
2063+
[&](SubstitutableType *type) -> Type {
2064+
auto *gp = cast<GenericTypeParamType>(type);
2065+
if (gp->getDepth() < superclassDepth)
2066+
return Type(gp).subst(subMap);
2067+
return CanGenericTypeParamType::get(
2068+
gp->getDepth() - superclassDepth + depth,
2069+
gp->getIndex(),
2070+
ctx);
2071+
},
2072+
[&](CanType depTy, Type substTy, ProtocolDecl *proto)
2073+
-> Optional<ProtocolConformanceRef> {
2074+
if (auto conf = subMap.lookupConformance(depTy, proto))
2075+
return conf;
2076+
2077+
return ProtocolConformanceRef(proto);
2078+
});
2079+
}
2080+
2081+
// We don't have to clone the requirements, because they're not
2082+
// used for anything.
2083+
genericParams = GenericParamList::create(ctx,
2084+
SourceLoc(),
2085+
newParams,
2086+
SourceLoc(),
2087+
ArrayRef<RequirementRepr>(),
2088+
SourceLoc());
2089+
genericParams->setOuterParameters(classDecl->getGenericParamsOfContext());
2090+
2091+
GenericSignatureBuilder builder(ctx);
2092+
builder.addGenericSignature(classDecl->getGenericSignature());
2093+
2094+
for (auto *newParam : newParams)
2095+
builder.addGenericParameter(newParam);
2096+
2097+
auto source =
2098+
GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
2099+
for (auto reqt : superclassSig->getRequirements())
2100+
if (auto substReqt = reqt.subst(subMap))
2101+
builder.addRequirement(*substReqt, source, nullptr);
2102+
2103+
genericSig = std::move(builder).computeGenericSignature(SourceLoc());
2104+
genericEnv = genericSig->createGenericEnvironment();
2105+
} else {
2106+
genericEnv = classDecl->getGenericEnvironment();
2107+
genericSig = classDecl->getGenericSignature();
2108+
}
2109+
2110+
return std::make_tuple(genericSig, genericEnv, genericParams, subMap);
2111+
}
2112+
20142113
static void configureDesignatedInitAttributes(TypeChecker &tc,
20152114
ClassDecl *classDecl,
20162115
ConstructorDecl *ctor,
@@ -2088,9 +2187,7 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20882187
ClassDecl *classDecl,
20892188
ConstructorDecl *superclassCtor,
20902189
DesignatedInitKind kind) {
2091-
// FIXME: Inheriting initializers that have their own generic parameters
2092-
if (superclassCtor->getGenericParams())
2093-
return nullptr;
2190+
auto &ctx = tc.Context;
20942191

20952192
// Lookup will sometimes give us initializers that are from the ancestors of
20962193
// our immediate superclass. So, from the superclass constructor, we look
@@ -2104,54 +2201,42 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21042201
superclassCtor->getDeclContext()
21052202
->getAsNominalTypeOrNominalTypeExtensionContext();
21062203
Type superclassTy = classDecl->getSuperclass();
2107-
Type superclassTyInContext = classDecl->mapTypeIntoContext(superclassTy);
21082204
NominalTypeDecl *superclassDecl = superclassTy->getAnyNominal();
21092205
if (superclassCtorDecl != superclassDecl) {
21102206
return nullptr;
21112207
}
21122208

2209+
GenericSignature *genericSig;
2210+
GenericEnvironment *genericEnv;
2211+
GenericParamList *genericParams;
2212+
SubstitutionMap subMap;
2213+
2214+
std::tie(genericSig, genericEnv, genericParams, subMap) =
2215+
configureGenericDesignatedInitOverride(ctx,
2216+
classDecl,
2217+
superclassTy,
2218+
superclassCtor);
2219+
21132220
// Determine the initializer parameters.
2114-
auto &ctx = tc.Context;
21152221

21162222
// Create the 'self' declaration and patterns.
21172223
auto *selfDecl = ParamDecl::createSelf(SourceLoc(), classDecl);
21182224

21192225
// Create the initializer parameter patterns.
21202226
OptionSet<ParameterList::CloneFlags> options = ParameterList::Implicit;
21212227
options |= ParameterList::Inherited;
2122-
auto *bodyParams = superclassCtor->getParameterList(1)->clone(ctx,options);
2228+
auto *bodyParams = superclassCtor->getParameterList(1)->clone(ctx, options);
21232229

21242230
// If the superclass is generic, we need to map the superclass constructor's
21252231
// parameter types into the generic context of our class.
21262232
//
21272233
// We might have to apply substitutions, if for example we have a declaration
21282234
// like 'class A : B<Int>'.
2129-
if (superclassDecl->getGenericSignatureOfContext()) {
2130-
auto *moduleDecl = classDecl->getParentModule();
2131-
auto subMap = superclassTyInContext->getContextSubstitutionMap(
2132-
moduleDecl,
2133-
superclassDecl,
2134-
classDecl->getGenericEnvironment());
2135-
2136-
for (auto *decl : *bodyParams) {
2137-
auto paramTy = decl->getInterfaceType()->getInOutObjectType();
2138-
2139-
// Apply the superclass substitutions to produce a contextual
2140-
// type in terms of the derived class archetypes.
2141-
auto paramSubstTy = paramTy.subst(subMap);
2142-
decl->setType(paramSubstTy);
2143-
2144-
// Map it to an interface type in terms of the derived class
2145-
// generic signature.
2146-
decl->setInterfaceType(paramSubstTy->mapTypeOutOfContext());
2147-
}
2148-
} else {
2149-
for (auto *decl : *bodyParams) {
2150-
if (!decl->hasType())
2151-
decl->setType(
2152-
classDecl->mapTypeIntoContext(
2153-
decl->getInterfaceType()->getInOutObjectType()));
2154-
}
2235+
for (auto *decl : *bodyParams) {
2236+
auto paramTy = decl->getInterfaceType();
2237+
auto substTy = paramTy.subst(subMap);
2238+
decl->setInterfaceType(substTy);
2239+
decl->setType(GenericEnvironment::mapTypeIntoContext(genericEnv, substTy));
21552240
}
21562241

21572242
// Create the initializer declaration, inheriting the name,
@@ -2164,13 +2249,14 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21642249
/*Throws=*/superclassCtor->hasThrows(),
21652250
/*ThrowsLoc=*/SourceLoc(),
21662251
selfDecl, bodyParams,
2167-
/*GenericParams=*/nullptr, classDecl);
2252+
genericParams, classDecl);
21682253

21692254
ctor->setImplicit();
21702255

21712256
// Set the interface type of the initializer.
2172-
ctor->setGenericEnvironment(classDecl->getGenericEnvironmentOfContext());
2173-
tc.configureInterfaceType(ctor, ctor->getGenericSignature());
2257+
ctor->setGenericEnvironment(genericEnv);
2258+
2259+
tc.configureInterfaceType(ctor, genericSig);
21742260
ctor->setValidationStarted();
21752261

21762262
configureDesignatedInitAttributes(tc, classDecl,

0 commit comments

Comments
 (0)