Skip to content

Commit 2f0c8a8

Browse files
committed
Sema: Implement inheritance of initializers with generic parameters
Fixes <https://bugs.swift.org/browse/SR-3848>.
1 parent 8606d3e commit 2f0c8a8

File tree

4 files changed

+242
-108
lines changed

4 files changed

+242
-108
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 115 additions & 12 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,104 @@ 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+
// Substitution map that maps the generic parameters of the superclass
2046+
// to the generic parameters of the derived class, and the generic
2047+
// parameters of the superclass initializer to the generic parameters
2048+
// of the derived class initializer.
2049+
auto *superclassSig = superclassCtor->getGenericSignature();
2050+
if (superclassSig) {
2051+
unsigned superclassDepth = 0;
2052+
if (auto *genericSig = superclassDecl->getGenericSignature())
2053+
superclassDepth = genericSig->getGenericParams().back()->getDepth() + 1;
2054+
2055+
subMap = superclassSig->getSubstitutionMap(
2056+
[&](SubstitutableType *type) -> Type {
2057+
auto *gp = cast<GenericTypeParamType>(type);
2058+
if (gp->getDepth() < superclassDepth)
2059+
return Type(gp).subst(subMap);
2060+
return CanGenericTypeParamType::get(
2061+
gp->getDepth() - superclassDepth + depth,
2062+
gp->getIndex(),
2063+
ctx);
2064+
},
2065+
[&](CanType depTy, Type substTy, ProtocolType *protoType)
2066+
-> Optional<ProtocolConformanceRef> {
2067+
auto *proto = protoType->getDecl();
2068+
if (auto conf = subMap.lookupConformance(depTy, proto))
2069+
return conf;
2070+
2071+
return ProtocolConformanceRef(proto);
2072+
});
2073+
}
2074+
2075+
// We don't have to clone the requirements, because they're not
2076+
// used for anything.
2077+
genericParams = GenericParamList::create(ctx,
2078+
SourceLoc(),
2079+
newParams,
2080+
SourceLoc(),
2081+
ArrayRef<RequirementRepr>(),
2082+
SourceLoc());
2083+
genericParams->setOuterParameters(classDecl->getGenericParamsOfContext());
2084+
2085+
GenericSignatureBuilder builder(ctx);
2086+
builder.addGenericSignature(classDecl->getGenericSignature());
2087+
2088+
for (auto *newParam : newParams)
2089+
builder.addGenericParameter(newParam);
2090+
2091+
auto source =
2092+
GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
2093+
for (auto reqt : superclassSig->getRequirements())
2094+
if (auto substReqt = reqt.subst(subMap))
2095+
builder.addRequirement(*substReqt, source, nullptr);
2096+
2097+
genericSig = std::move(builder).computeGenericSignature(SourceLoc());
2098+
genericEnv = genericSig->createGenericEnvironment();
2099+
} else {
2100+
genericEnv = classDecl->getGenericEnvironment();
2101+
genericSig = classDecl->getGenericSignature();
2102+
}
2103+
2104+
return std::make_tuple(genericSig, genericEnv, genericParams, subMap);
2105+
}
2106+
20082107
static void configureDesignatedInitAttributes(TypeChecker &tc,
20092108
ClassDecl *classDecl,
20102109
ConstructorDecl *ctor,
@@ -2084,10 +2183,6 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20842183
DesignatedInitKind kind) {
20852184
auto &ctx = tc.Context;
20862185

2087-
// FIXME: Inheriting initializers that have their own generic parameters
2088-
if (superclassCtor->getGenericParams())
2089-
return nullptr;
2090-
20912186
// Lookup will sometimes give us initializers that are from the ancestors of
20922187
// our immediate superclass. So, from the superclass constructor, we look
20932188
// one level up to the enclosing type context which will either be a class
@@ -2105,6 +2200,17 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21052200
return nullptr;
21062201
}
21072202

2203+
GenericSignature *genericSig;
2204+
GenericEnvironment *genericEnv;
2205+
GenericParamList *genericParams;
2206+
SubstitutionMap subMap;
2207+
2208+
std::tie(genericSig, genericEnv, genericParams, subMap) =
2209+
configureGenericDesignatedInitOverride(ctx,
2210+
classDecl,
2211+
superclassTy,
2212+
superclassCtor);
2213+
21082214
// Determine the initializer parameters.
21092215

21102216
// Create the 'self' declaration and patterns.
@@ -2120,15 +2226,11 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21202226
//
21212227
// We might have to apply substitutions, if for example we have a declaration
21222228
// like 'class A : B<Int>'.
2123-
auto *moduleDecl = classDecl->getParentModule();
2124-
auto subMap = superclassTy->getContextSubstitutionMap(
2125-
moduleDecl, superclassDecl);
2126-
21272229
for (auto *decl : *bodyParams) {
21282230
auto paramTy = decl->getInterfaceType()->getInOutObjectType();
21292231
auto substTy = paramTy.subst(subMap);
21302232
decl->setInterfaceType(substTy);
2131-
decl->setType(classDecl->mapTypeIntoContext(substTy));
2233+
decl->setType(GenericEnvironment::mapTypeIntoContext(genericEnv, substTy));
21322234
}
21332235

21342236
// Create the initializer declaration, inheriting the name,
@@ -2141,13 +2243,14 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21412243
/*Throws=*/superclassCtor->hasThrows(),
21422244
/*ThrowsLoc=*/SourceLoc(),
21432245
selfDecl, bodyParams,
2144-
/*GenericParams=*/nullptr, classDecl);
2246+
genericParams, classDecl);
21452247

21462248
ctor->setImplicit();
21472249

21482250
// Set the interface type of the initializer.
2149-
ctor->setGenericEnvironment(classDecl->getGenericEnvironmentOfContext());
2150-
tc.configureInterfaceType(ctor, ctor->getGenericSignature());
2251+
ctor->setGenericEnvironment(genericEnv);
2252+
2253+
tc.configureInterfaceType(ctor, genericSig);
21512254
ctor->setValidationStarted();
21522255

21532256
configureDesignatedInitAttributes(tc, classDecl,
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership %s -verify
2+
3+
// We just want to SILGen this and ensure it doesn't crash. Don't particularly
4+
// care about the generated SIL.
5+
6+
// Inheritance of unnamed parameters.
7+
class SuperUnnamed {
8+
init(int _: Int) { }
9+
init(_ : Double) { }
10+
11+
init(string _: String) { }
12+
init(_ : Float) { }
13+
}
14+
15+
class SubUnnamed : SuperUnnamed { }
16+
17+
func testSubUnnamed(_ i: Int, d: Double, s: String, f: Float) {
18+
_ = SubUnnamed(int: i)
19+
_ = SubUnnamed(d)
20+
_ = SubUnnamed(string: s)
21+
_ = SubUnnamed(f)
22+
}
23+
24+
// rdar://problem/17960407 - Inheritance of initializers for generic types
25+
class ConcreteBase {
26+
required init(i: Int) {}
27+
}
28+
29+
class GenericDerived<T> : ConcreteBase {}
30+
31+
class GenericBase<T> {
32+
required init(t: T) {}
33+
}
34+
35+
class GenericDerived2<U> : GenericBase<(U, U)> {}
36+
37+
class ConcreteDerived : GenericBase<Int> {}
38+
39+
func testGenericInheritance() {
40+
_ = GenericDerived<Int>(i: 10)
41+
_ = GenericDerived2<Int>(t: (10, 100))
42+
_ = ConcreteDerived(t: 1000)
43+
}
44+
45+
// rdar://problem/34789779 - Inheritance of initializers with inout parameters
46+
public class Node {
47+
var data : Data
48+
49+
public struct Data {
50+
var index: Int32 = 0// for helpers
51+
}
52+
53+
init(data: inout Data/*, context: Context*/) {
54+
self.data = data
55+
}
56+
57+
public required init(node: Node) {
58+
data = node.data
59+
}
60+
}
61+
62+
class SubNode : Node {
63+
var a: Int
64+
65+
required init(node: Node) {
66+
a = 1
67+
super.init(node: node)
68+
}
69+
70+
init(data: inout Data, additionalParam: Int) {
71+
a = additionalParam
72+
super.init(data: &data)
73+
}
74+
}
75+
76+
class GenericSubNode<T> : SubNode {
77+
required init(node: Node) {
78+
super.init(node: node)
79+
}
80+
81+
init(data: inout Data, value: T) {
82+
super.init(data: &data, additionalParam: 1)
83+
}
84+
}
85+
86+
protocol HasValue {
87+
associatedtype Value
88+
func getValue() -> Value
89+
}
90+
91+
class GenericWrapperNode<T : HasValue> : GenericSubNode<T.Value> {
92+
required init(node: Node) {
93+
super.init(node: node)
94+
}
95+
96+
init(data: inout Data, otherValue: T) {
97+
super.init(data: &data, value: otherValue.getValue())
98+
}
99+
}
100+
101+
// https://bugs.swift.org/browse/SR-3848 - Initializer with generic parameter
102+
protocol P {
103+
associatedtype T
104+
}
105+
106+
struct S<T> : P {}
107+
108+
class Outer<T> {
109+
class Inner<U> where U : P {
110+
init<V>(_: V) where V : P, V.T == U {}
111+
}
112+
}
113+
114+
class Derived<X> : Outer<X>.Inner<S<X>> {}
115+
116+
protocol Q {
117+
associatedtype A
118+
associatedtype B
119+
}
120+
121+
class Twice<X, Y> {
122+
init<Z>(_: Z) where Z : Q, Z.A == X, Z.B == Y, X == Y {}
123+
}
124+
125+
class Once<T> : Twice<T, T> {}

test/SILGen/vtable_thunks_reabstraction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ class MoreGenericSub1<T, TT> : GenericBase<T> {
541541

542542
// CHECK-LABEL: sil_vtable MoreGenericSub1 {
543543
// CHECK-NEXT: #GenericBase.doStuff!1: <T><U> (GenericBase<T>) -> (T, U) -> () : @$S27vtable_thunks_reabstraction15MoreGenericSub1C7doStuff1t1uyx_qd__tlF [override] // MoreGenericSub1.doStuff<A>(t:u:)
544-
// CHECK-NEXT: #GenericBase.init!initializer.1: <T><U> (GenericBase<T>.Type) -> (T, U) -> GenericBase<T> : @$S27vtable_thunks_reabstraction11GenericBaseC1t1uACyxGx_qd__tclufc [inherited] // GenericBase.init<A>(t:u:)
544+
// CHECK-NEXT: #GenericBase.init!initializer.1: <T><U> (GenericBase<T>.Type) -> (T, U) -> GenericBase<T> : @$S27vtable_thunks_reabstraction15MoreGenericSub1C1t1uACyxq_Gx_qd__tclufc [override] // MoreGenericSub1.init<A>(t:u:)
545545
// CHECK-NEXT: #MoreGenericSub1.deinit!deallocator: @$S27vtable_thunks_reabstraction15MoreGenericSub1CfD // MoreGenericSub1.__deallocating_deinit
546546
// CHECK-NEXT: }
547547

@@ -553,6 +553,6 @@ class MoreGenericSub2<TT, T> : GenericBase<T> {
553553

554554
// CHECK-LABEL: sil_vtable MoreGenericSub2 {
555555
// CHECK-NEXT: #GenericBase.doStuff!1: <T><U> (GenericBase<T>) -> (T, U) -> () : @$S27vtable_thunks_reabstraction15MoreGenericSub2C7doStuff1t1uyq__qd__tlF [override] // MoreGenericSub2.doStuff<A>(t:u:)
556-
// CHECK-NEXT: #GenericBase.init!initializer.1: <T><U> (GenericBase<T>.Type) -> (T, U) -> GenericBase<T> : @$S27vtable_thunks_reabstraction11GenericBaseC1t1uACyxGx_qd__tclufc [inherited] // GenericBase.init<A>(t:u:)
556+
// CHECK-NEXT: #GenericBase.init!initializer.1: <T><U> (GenericBase<T>.Type) -> (T, U) -> GenericBase<T> : @$S27vtable_thunks_reabstraction15MoreGenericSub2C1t1uACyxq_Gq__qd__tclufc [override] // MoreGenericSub2.init<A>(t:u:)
557557
// CHECK-NEXT: #MoreGenericSub2.deinit!deallocator: @$S27vtable_thunks_reabstraction15MoreGenericSub2CfD // MoreGenericSub2.__deallocating_deinit
558558
// CHECK-NEXT: }

0 commit comments

Comments
 (0)