Skip to content

Commit 5511c09

Browse files
authored
Merge pull request #17390 from slavapestov/generic-init-inheritance-4.2
Implement inheritance of initializers with generic parameters [4.2]
2 parents f0b9a8b + 09aea61 commit 5511c09

File tree

6 files changed

+277
-154
lines changed

6 files changed

+277
-154
lines changed

lib/AST/Type.cpp

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

32753275
// Gather all of the substitutions for all levels of generic arguments.
3276-
GenericParamList *curGenericParams = dc->getGenericParamsOfContext();
3277-
if (!curGenericParams)
3276+
auto *genericSig = dc->getGenericSignatureOfContext();
3277+
if (!genericSig)
32783278
return substitutions;
32793279

3280-
while (baseTy && curGenericParams) {
3280+
auto params = genericSig->getGenericParams();
3281+
unsigned n = params.size();
3282+
3283+
while (baseTy && n > 0) {
32813284
// For a bound generic type, gather the generic parameter -> generic
32823285
// argument substitutions.
32833286
if (auto boundGeneric = baseTy->getAs<BoundGenericType>()) {
3284-
auto params = curGenericParams->getParams();
32853287
auto args = boundGeneric->getGenericArgs();
3286-
for (unsigned i = 0, n = args.size(); i != n; ++i) {
3287-
substitutions[params[i]->getDeclaredInterfaceType()->getCanonicalType()
3288+
for (unsigned i = 0, e = args.size(); i < e; ++i) {
3289+
substitutions[params[n - e + i]->getCanonicalType()
32883290
->castTo<GenericTypeParamType>()] = args[i];
32893291
}
32903292

32913293
// Continue looking into the parent.
32923294
baseTy = boundGeneric->getParent();
3293-
curGenericParams = curGenericParams->getOuterParameters();
3295+
n -= args.size();
32943296
continue;
32953297
}
32963298

32973299
// Continue looking into the parent.
32983300
if (auto protocolTy = baseTy->getAs<ProtocolType>()) {
32993301
baseTy = protocolTy->getParent();
3300-
curGenericParams = curGenericParams->getOuterParameters();
3302+
n--;
33013303
continue;
33023304
}
33033305

@@ -3310,19 +3312,16 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
33103312
llvm_unreachable("Bad base type");
33113313
}
33123314

3313-
if (genericEnv) {
3314-
auto *parentDC = dc;
3315-
while (parentDC->isTypeContext())
3316-
parentDC = parentDC->getParent();
3317-
if (auto *outerSig = parentDC->getGenericSignatureOfContext()) {
3318-
for (auto gp : outerSig->getGenericParams()) {
3319-
auto result = substitutions.insert(
3320-
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
3321-
genericEnv->mapTypeIntoContext(gp)});
3322-
assert(result.second);
3323-
(void) result;
3324-
}
3325-
}
3315+
while (n > 0) {
3316+
auto *gp = params[--n];
3317+
auto substTy = (genericEnv
3318+
? genericEnv->mapTypeIntoContext(gp)
3319+
: gp);
3320+
auto result = substitutions.insert(
3321+
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
3322+
substTy});
3323+
assert(result.second);
3324+
(void) result;
33263325
}
33273326

33283327
return substitutions;

lib/Sema/CodeSynthesis.cpp

Lines changed: 126 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"
@@ -2005,6 +2006,109 @@ static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) {
20052006
ctor->setStubImplementation(true);
20062007
}
20072008

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

20892191
// Lookup will sometimes give us initializers that are from the ancestors of
20902192
// our immediate superclass. So, from the superclass constructor, we look
@@ -2098,54 +2200,42 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20982200
superclassCtor->getDeclContext()
20992201
->getAsNominalTypeOrNominalTypeExtensionContext();
21002202
Type superclassTy = classDecl->getSuperclass();
2101-
Type superclassTyInContext = classDecl->mapTypeIntoContext(superclassTy);
21022203
NominalTypeDecl *superclassDecl = superclassTy->getAnyNominal();
21032204
if (superclassCtorDecl != superclassDecl) {
21042205
return nullptr;
21052206
}
21062207

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

21102221
// Create the 'self' declaration and patterns.
21112222
auto *selfDecl = ParamDecl::createSelf(SourceLoc(), classDecl);
21122223

21132224
// Create the initializer parameter patterns.
21142225
OptionSet<ParameterList::CloneFlags> options = ParameterList::Implicit;
21152226
options |= ParameterList::Inherited;
2116-
auto *bodyParams = superclassCtor->getParameterList(1)->clone(ctx,options);
2227+
auto *bodyParams = superclassCtor->getParameterList(1)->clone(ctx, options);
21172228

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

21512241
// Create the initializer declaration, inheriting the name,
@@ -2158,13 +2248,14 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21582248
/*Throws=*/superclassCtor->hasThrows(),
21592249
/*ThrowsLoc=*/SourceLoc(),
21602250
selfDecl, bodyParams,
2161-
/*GenericParams=*/nullptr, classDecl);
2251+
genericParams, classDecl);
21622252

21632253
ctor->setImplicit();
21642254

21652255
// Set the interface type of the initializer.
2166-
ctor->setGenericEnvironment(classDecl->getGenericEnvironmentOfContext());
2167-
tc.configureInterfaceType(ctor, ctor->getGenericSignature());
2256+
ctor->setGenericEnvironment(genericEnv);
2257+
2258+
tc.configureInterfaceType(ctor, genericSig);
21682259
ctor->setValidationStarted();
21692260

21702261
configureDesignatedInitAttributes(tc, classDecl,

0 commit comments

Comments
 (0)