Skip to content

Commit 0e91735

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

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"
@@ -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,
@@ -2090,10 +2189,6 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20902189
DesignatedInitKind kind) {
20912190
auto &ctx = tc.Context;
20922191

2093-
// FIXME: Inheriting initializers that have their own generic parameters
2094-
if (superclassCtor->getGenericParams())
2095-
return nullptr;
2096-
20972192
// Lookup will sometimes give us initializers that are from the ancestors of
20982193
// our immediate superclass. So, from the superclass constructor, we look
20992194
// one level up to the enclosing type context which will either be a class
@@ -2111,6 +2206,17 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21112206
return nullptr;
21122207
}
21132208

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+
21142220
// Determine the initializer parameters.
21152221

21162222
// Create the 'self' declaration and patterns.
@@ -2126,15 +2232,11 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21262232
//
21272233
// We might have to apply substitutions, if for example we have a declaration
21282234
// like 'class A : B<Int>'.
2129-
auto *moduleDecl = classDecl->getParentModule();
2130-
auto subMap = superclassTy->getContextSubstitutionMap(
2131-
moduleDecl, superclassDecl);
2132-
21332235
for (auto *decl : *bodyParams) {
21342236
auto paramTy = decl->getInterfaceType();
21352237
auto substTy = paramTy.subst(subMap);
21362238
decl->setInterfaceType(substTy);
2137-
decl->setType(classDecl->mapTypeIntoContext(substTy));
2239+
decl->setType(GenericEnvironment::mapTypeIntoContext(genericEnv, substTy));
21382240
}
21392241

21402242
// Create the initializer declaration, inheriting the name,
@@ -2147,13 +2249,14 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
21472249
/*Throws=*/superclassCtor->hasThrows(),
21482250
/*ThrowsLoc=*/SourceLoc(),
21492251
selfDecl, bodyParams,
2150-
/*GenericParams=*/nullptr, classDecl);
2252+
genericParams, classDecl);
21512253

21522254
ctor->setImplicit();
21532255

21542256
// Set the interface type of the initializer.
2155-
ctor->setGenericEnvironment(classDecl->getGenericEnvironmentOfContext());
2156-
tc.configureInterfaceType(ctor, ctor->getGenericSignature());
2257+
ctor->setGenericEnvironment(genericEnv);
2258+
2259+
tc.configureInterfaceType(ctor, genericSig);
21572260
ctor->setValidationStarted();
21582261

21592262
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-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)