Skip to content

Commit 0ff0f3c

Browse files
committed
Sema: Generic classes and subclasses of generic classes now inherit required initializers
Initializers are inherited by synthesizing an implicit decl which delegates to super.init(). Previously this was only done if the class and superclass were concrete. The only thing missing was that we weren't computing an interface type for the synthesized constructor. There are two steps to this: - First, we must map the contextual types of the superclass initializer's ParamDecls to the subclass generic context. - Second, we must set the interface type by calling the new configureInterfaceType() method, extracted from from validateGenericSignature(). Note that configureInterfaceType() now uses the new AbstractFunctionDecl::hasThrows() flag to set the 'throws' bit on the function type. Previously, validateGenericFuncSignature() would look at getThrowsLoc().isValid(), which is not correct for imported, implicitly-generated or de-serialized decls that 'throw', because none of those have source location information. We still don't allow inheriting initializers which have their own generic parameter list, like 'init<T>(t: T) {...}'. That requires a little bit more refactoring. Progress on <rdar://problem/23376955>.
1 parent 459e3b0 commit 0ff0f3c

File tree

10 files changed

+181
-88
lines changed

10 files changed

+181
-88
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,14 +2040,11 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20402040
ClassDecl *classDecl,
20412041
ConstructorDecl *superclassCtor,
20422042
DesignatedInitKind kind) {
2043-
// Determine the initializer parameters.
2044-
Type superInitType = superclassCtor->getInitializerInterfaceType();
2045-
if (superInitType->is<GenericFunctionType>() ||
2046-
classDecl->getGenericParamsOfContext()) {
2047-
// FIXME: Handle generic initializers as well.
2043+
// FIXME: Inheriting initializers that have their own generic parameters
2044+
if (superclassCtor->getGenericParams())
20482045
return nullptr;
2049-
}
20502046

2047+
// Determine the initializer parameters.
20512048
auto &ctx = tc.Context;
20522049

20532050
// Create the 'self' declaration and patterns.
@@ -2057,8 +2054,40 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20572054
OptionSet<ParameterList::CloneFlags> options = ParameterList::Implicit;
20582055
options |= ParameterList::Inherited;
20592056
auto *bodyParams = superclassCtor->getParameterList(1)->clone(ctx,options);
2060-
2061-
// Create the initializer declaration.
2057+
2058+
// If the superclass is generic, we need to map the superclass constructor's
2059+
// parameter types into the generic context of our class.
2060+
//
2061+
// We might have to apply substitutions, if for example we have a declaration
2062+
// like 'class A : B<Int>'.
2063+
auto superclassTy = classDecl->getSuperclass();
2064+
auto *superclassDecl = superclassTy->getAnyNominal();
2065+
if (superclassDecl->isGenericTypeContext()) {
2066+
if (auto *superclassSig = superclassDecl->getGenericSignatureOfContext()) {
2067+
auto *moduleDecl = classDecl->getParentModule();
2068+
auto subs = superclassTy->gatherAllSubstitutions(
2069+
moduleDecl, nullptr, nullptr);
2070+
auto subsMap = superclassSig->getSubstitutionMap(subs);
2071+
2072+
for (auto *decl : *bodyParams) {
2073+
// Map the parameter type to an interface type written in terms of
2074+
// the superclass generic signature.
2075+
auto paramTy = ArchetypeBuilder::mapTypeOutOfContext(
2076+
superclassDecl, decl->getType());
2077+
2078+
// Apply the superclass substitutions to produce an interface
2079+
// type in terms of the class generic signature.
2080+
auto paramSubstTy = paramTy.subst(moduleDecl, subsMap, SubstOptions());
2081+
2082+
// Map it to a contextual type in terms of the class's archetypes.
2083+
decl->overwriteType(ArchetypeBuilder::mapTypeIntoContext(
2084+
classDecl, paramSubstTy));
2085+
}
2086+
}
2087+
}
2088+
2089+
// Create the initializer declaration, inheriting the name,
2090+
// failability, and throws from the superclass initializer.
20622091
auto ctor =
20632092
new (ctx) ConstructorDecl(superclassCtor->getFullName(),
20642093
classDecl->getBraces().Start,
@@ -2068,20 +2097,27 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20682097
/*ThrowsLoc=*/SourceLoc(),
20692098
selfDecl, bodyParams,
20702099
/*GenericParams=*/nullptr, classDecl);
2100+
20712101
ctor->setImplicit();
20722102
ctor->setAccessibility(std::min(classDecl->getFormalAccess(),
20732103
superclassCtor->getFormalAccess()));
20742104

20752105
// Make sure the constructor is only as available as its superclass's
20762106
// constructor.
2077-
AvailabilityInference::applyInferredAvailableAttrs(ctor, superclassCtor,
2078-
ctx);
2107+
AvailabilityInference::applyInferredAvailableAttrs(ctor, superclassCtor, ctx);
20792108

20802109
// Configure 'self'.
20812110
auto selfType = configureImplicitSelf(tc, ctor);
20822111

2083-
// Set the type of the initializer.
2112+
// Set the interface type of the initializer.
2113+
if (classDecl->isGenericTypeContext()) {
2114+
ctor->setGenericSignature(classDecl->getGenericSignatureOfContext());
2115+
tc.configureInterfaceType(ctor);
2116+
}
2117+
2118+
// Set the contextual type of the initializer. This will go away one day.
20842119
configureConstructorType(ctor, selfType, bodyParams->getType(ctx));
2120+
20852121
if (superclassCtor->isObjC()) {
20862122
// Inherit the @objc name from the superclass initializer, if it
20872123
// has one.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7446,8 +7446,7 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
74467446
classDecl->getSuperclass()->getAnyNominal()->isInvalid() ||
74477447
classDecl->getSuperclass()->getAnyNominal()
74487448
->addedImplicitInitializers());
7449-
if (classDecl->hasSuperclass() && !classDecl->isGenericContext() &&
7450-
!classDecl->getSuperclass()->isSpecialized()) {
7449+
if (classDecl->hasSuperclass()) {
74517450
bool canInheritInitializers = !FoundDesignatedInit;
74527451

74537452
// We can't define these overrides if we have any uninitialized

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -553,9 +553,16 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
553553
return true;
554554
}
555555

556-
// Compute the function type.
556+
configureInterfaceType(func);
557+
return false;
558+
}
559+
560+
void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func) {
557561
Type funcTy;
558562
Type initFuncTy;
563+
564+
auto *sig = func->getGenericSignature();
565+
559566
if (auto fn = dyn_cast<FuncDecl>(func)) {
560567
funcTy = fn->getBodyResultTypeLoc().getType();
561568

@@ -631,73 +638,11 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
631638
// to begin with, but fixing that requires a lot of reengineering for local
632639
// definitions in generic contexts.
633640
if (sig && i == e-1) {
634-
if (func->getGenericParams()) {
635-
// Collect all generic params referenced in parameter types,
636-
// return type or requirements.
637-
SmallPtrSet<GenericTypeParamDecl *, 4> referencedGenericParams;
638-
argTy.visit([&referencedGenericParams](Type t) {
639-
if (isa<GenericTypeParamType>(t.getCanonicalTypeOrNull())) {
640-
referencedGenericParams.insert(
641-
t->castTo<GenericTypeParamType>()->getDecl());
642-
}
643-
});
644-
funcTy.visit([&referencedGenericParams](Type t) {
645-
if (isa<GenericTypeParamType>(t.getCanonicalTypeOrNull())) {
646-
referencedGenericParams.insert(
647-
t->castTo<GenericTypeParamType>()->getDecl());
648-
}
649-
});
650-
651-
auto requirements = sig->getRequirements();
652-
for (auto req : requirements) {
653-
if (req.getKind() == RequirementKind::SameType) {
654-
// Same type requirements may allow for generic
655-
// inference, even if this generic parameter
656-
// is not mentioned in the function signature.
657-
// TODO: Make the test more precise.
658-
auto left = req.getFirstType();
659-
auto right = req.getSecondType();
660-
// For now consider any references inside requirements
661-
// as a possibility to infer the generic type.
662-
left.visit([&referencedGenericParams](Type t) {
663-
if (isa<GenericTypeParamType>(t.getCanonicalTypeOrNull())) {
664-
referencedGenericParams.insert(
665-
t->castTo<GenericTypeParamType>()->getDecl());
666-
}
667-
});
668-
right.visit([&referencedGenericParams](Type t) {
669-
if (isa<GenericTypeParamType>(t.getCanonicalTypeOrNull())) {
670-
referencedGenericParams.insert(
671-
t->castTo<GenericTypeParamType>()->getDecl());
672-
}
673-
});
674-
}
675-
}
676-
677-
// Find the depth of the function's own generic parameters.
678-
unsigned fnGenericParamsDepth = func->getGenericParams()->getDepth();
679-
680-
// Check that every generic parameter type from the signature is
681-
// among referencedArchetypes.
682-
for (auto *genParam : sig->getGenericParams()) {
683-
auto *paramDecl = genParam->getDecl();
684-
if (paramDecl->getDepth() != fnGenericParamsDepth)
685-
continue;
686-
if (!referencedGenericParams.count(paramDecl)) {
687-
// Produce an error that this generic parameter cannot be bound.
688-
diagnose(paramDecl->getLoc(), diag::unreferenced_generic_parameter,
689-
paramDecl->getNameStr());
690-
func->setInvalid();
691-
}
692-
}
693-
}
694-
695641
funcTy = GenericFunctionType::get(sig, argTy, funcTy, info);
696642
if (initFuncTy)
697643
initFuncTy = GenericFunctionType::get(sig, initArgTy, initFuncTy, info);
698644
} else {
699645
funcTy = FunctionType::get(argTy, funcTy, info);
700-
701646
if (initFuncTy)
702647
initFuncTy = FunctionType::get(initArgTy, initFuncTy, info);
703648
}
@@ -707,7 +652,53 @@ bool TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
707652
func->setInterfaceType(funcTy);
708653
if (initFuncTy)
709654
cast<ConstructorDecl>(func)->setInitializerInterfaceType(initFuncTy);
710-
return false;
655+
656+
if (func->getGenericParams()) {
657+
// Collect all generic params referenced in parameter types,
658+
// return type or requirements.
659+
SmallPtrSet<GenericTypeParamDecl *, 4> referencedGenericParams;
660+
661+
auto visitorFn = [&referencedGenericParams](Type t) {
662+
if (auto *paramTy = t->getAs<GenericTypeParamType>())
663+
referencedGenericParams.insert(paramTy->getDecl());
664+
};
665+
666+
funcTy->castTo<AnyFunctionType>()->getInput().visit(visitorFn);
667+
funcTy->castTo<AnyFunctionType>()->getResult().visit(visitorFn);
668+
669+
auto requirements = sig->getRequirements();
670+
for (auto req : requirements) {
671+
if (req.getKind() == RequirementKind::SameType) {
672+
// Same type requirements may allow for generic
673+
// inference, even if this generic parameter
674+
// is not mentioned in the function signature.
675+
// TODO: Make the test more precise.
676+
auto left = req.getFirstType();
677+
auto right = req.getSecondType();
678+
// For now consider any references inside requirements
679+
// as a possibility to infer the generic type.
680+
left.visit(visitorFn);
681+
right.visit(visitorFn);
682+
}
683+
}
684+
685+
// Find the depth of the function's own generic parameters.
686+
unsigned fnGenericParamsDepth = func->getGenericParams()->getDepth();
687+
688+
// Check that every generic parameter type from the signature is
689+
// among referencedArchetypes.
690+
for (auto *genParam : sig->getGenericParams()) {
691+
auto *paramDecl = genParam->getDecl();
692+
if (paramDecl->getDepth() != fnGenericParamsDepth)
693+
continue;
694+
if (!referencedGenericParams.count(paramDecl)) {
695+
// Produce an error that this generic parameter cannot be bound.
696+
diagnose(paramDecl->getLoc(), diag::unreferenced_generic_parameter,
697+
paramDecl->getNameStr());
698+
func->setInvalid();
699+
}
700+
}
701+
}
711702
}
712703

713704
GenericSignature *TypeChecker::validateGenericSignature(

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,9 @@ class TypeChecker final : public LazyResolver {
921921

922922
void markInvalidGenericSignature(ValueDecl *VD);
923923

924+
/// Configure the interface type of a function declaration.
925+
void configureInterfaceType(AbstractFunctionDecl *func);
926+
924927
/// Validate the signature of a generic function.
925928
///
926929
/// \param func The generic function.

test/IRGen/generic_classes_objc.sil

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ bb0(%0 : $GenericInheritsObjC<T>):
3232
unreachable
3333
}
3434

35+
sil @_TToFC20generic_classes_objc19GenericInheritsObjCcfT7bellsOnSi_GSQGS0_x__ : $@convention(objc_method) <T> (Int, @owned GenericInheritsObjC<T>) -> @owned GenericInheritsObjC<T> {
36+
bb0(%0 : $Int, %1 : $GenericInheritsObjC<T>):
37+
unreachable
38+
}
39+
3540
// CHECK: @_TMPC20generic_classes_objc20GenericInheritsObjC2
3641

3742
class GenericInheritsObjC2<E> : Gizmo {
@@ -54,3 +59,8 @@ sil @_TToFC20generic_classes_objc20GenericInheritsObjC2cfT_GS0_x_ : $@convention
5459
bb0(%0 : $GenericInheritsObjC2<T>):
5560
unreachable
5661
}
62+
63+
sil @_TToFC20generic_classes_objc20GenericInheritsObjC2cfT7bellsOnSi_GSQGS0_x__ : $@convention(objc_method) <T> (Int, @owned GenericInheritsObjC<T>) -> @owned GenericInheritsObjC<T> {
64+
bb0(%0 : $Int, %1 : $GenericInheritsObjC<T>):
65+
unreachable
66+
}

test/IRGen/objc_generic_class_metadata.sil

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import objc_generics
1616
// CHECK: %objc_class* @"OBJC_CLASS_$_GenericClass"
1717
class Subclass: GenericClass<NSString> {}
1818

19+
sil_vtable Subclass {}
20+
1921
sil @metatype_sink : $@convention(thin) <T> (@thick T.Type) -> ()
2022
sil @objc_class_sink : $@convention(thin) <T: AnyObject> (@objc_metatype T.Type) -> ()
2123

@@ -54,6 +56,16 @@ entry:
5456
return undef : $()
5557
}
5658

59+
sil @_TToFC27objc_generic_class_metadata8SubclasscfT5thingGSQCSo8NSString__GSQS0__ : $@convention(objc_method) (ImplicitlyUnwrappedOptional<NSString>, @owned Subclass) -> @owned ImplicitlyUnwrappedOptional<Subclass> {
60+
entry(%0: $ImplicitlyUnwrappedOptional<NSString>, %1: $Subclass):
61+
unreachable
62+
}
63+
64+
sil @_TToFC27objc_generic_class_metadata8SubclasscfT_S0_ : $@convention(objc_method) (@owned Subclass) -> @owned Subclass {
65+
entry(%0: $Subclass):
66+
unreachable
67+
}
68+
5769
// CHECK-LABEL: define linkonce_odr hidden %swift.type* @_TMaCSo12GenericClass()
5870
// CHECK: [[T0:%.*]] = load %objc_class*, %objc_class** @"OBJC_CLASS_REF_$_GenericClass",
5971
// CHECK: call %objc_class* @rt_swift_getInitializedObjCClass(%objc_class* [[T0]])

test/Interpreter/classes.swift

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -173,20 +173,37 @@ print((b as Bank).deposit(Account(owner: "A")))
173173

174174
// rdar://25412647
175175

176-
private class Parent <T> {
177-
func doSomething() {
178-
overriddenMethod()
179-
}
176+
private class Parent<T> {
177+
required init() {}
180178

181-
func overriddenMethod() {
182-
fatalError("You should override this method in child class")
183-
}
179+
func doSomething() {
180+
overriddenMethod()
181+
}
182+
183+
func overriddenMethod() {
184+
fatalError("You should override this method in child class")
185+
}
184186
}
185187

186188
private class Child: Parent<String> {
187-
override func overriddenMethod() {
188-
print("Heaven!")
189-
}
189+
override func overriddenMethod() {
190+
print("Heaven!")
191+
}
190192
}
191193

192194
Child().doSomething() // CHECK: Heaven!
195+
196+
// rdar://23376955
197+
198+
protocol Makeable {
199+
init()
200+
func doSomething()
201+
}
202+
203+
extension Parent : Makeable {}
204+
205+
func makeOne<T : Makeable>(_: T.Type) -> T {
206+
return T()
207+
}
208+
209+
makeOne(Child.self).doSomething() // CHECK: Heaven!

test/SILGen/objc_thunks.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ class Wotsit<T> : Gizmo {
276276

277277
// Ivar destroyer
278278
// CHECK: sil hidden @_TToF{{.*}}WotsitE
279+
280+
// CHECK-LABEL: sil hidden [thunk] @_TToFC11objc_thunks6WotsitcfT_GSQGS0_x__ : $@convention(objc_method) <T> (@owned Wotsit<T>) -> @owned ImplicitlyUnwrappedOptional<Wotsit<T>>
281+
282+
// CHECK-LABEL: sil hidden [thunk] @_TToFC11objc_thunks6WotsitcfT7bellsOnSi_GSQGS0_x__ : $@convention(objc_method) <T> (Int, @owned Wotsit<T>) -> @owned ImplicitlyUnwrappedOptional<Wotsit<T>>
279283
}
280284

281285
// CHECK-NOT: sil hidden [thunk] @_TToF{{.*}}Wotsit{{.*}}

test/decl/inherit/initializer.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,27 @@ func testSubUnnamed(_ i: Int, d: Double, s: String, f: Float) {
110110
_ = SubUnnamed(f)
111111
}
112112

113+
// rdar://problem/17960407 - Inheritance of generic initializers
114+
class ConcreteBase {
115+
required init(i: Int) {}
116+
}
117+
118+
class GenericDerived<T> : ConcreteBase {}
119+
120+
class GenericBase<T> {
121+
required init(t: T) {}
122+
}
123+
124+
class GenericDerived2<U> : GenericBase<(U, U)> {}
125+
126+
class ConcreteDerived : GenericBase<Int> {}
127+
128+
func testGenericInheritance() {
129+
_ = GenericDerived<Int>(i: 10)
130+
_ = GenericDerived2<Int>(t: (10, 100))
131+
_ = ConcreteDerived(t: 1000)
132+
}
133+
113134
// FIXME: <rdar://problem/16331406> Implement inheritance of variadic designated initializers
114135
class SuperVariadic {
115136
init(ints: Int...) { } // expected-note{{variadic superclass initializer defined here}}

0 commit comments

Comments
 (0)