Skip to content

Commit 379220b

Browse files
committed
Sema: Fix a couple of issues with implicit overrides of generic designated initializers
If a base class initializer was not generic but had a contextual 'where' clause, we would unconditionally inherit the 'where' clause in the override as part of the fix for another issue (https://bugs.swift.org/browse/SR-14118). However, it is possible that some of those requirements are satisfied by the derived class itself. For example: class Base<T> { init() where T : AnyObject {} } class Derived : Base<AnyObject> {} In this case, the implicit override Derived.init() has no generic requirements at all. We used to assert because we would create a GSB with no generic parameters. It was also possible for a base class initializer to have generic requirements that are not satisfied by the derived class. In this case, we need to drop the initializer from consideration altogether. While I'm here, I improved the comments in computeDesignatedInitOverrideSignature(), which is the new name for configureGenericDesignatedInitOverride(). Fixes rdar://problem/77285618.
1 parent 161c837 commit 379220b

File tree

2 files changed

+126
-53
lines changed

2 files changed

+126
-53
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 97 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -418,30 +418,49 @@ synthesizeStubBody(AbstractFunctionDecl *fn, void *) {
418418
/*isTypeChecked=*/true };
419419
}
420420

421-
static std::tuple<GenericSignature, GenericParamList *, SubstitutionMap>
422-
configureGenericDesignatedInitOverride(ASTContext &ctx,
421+
namespace {
422+
struct DesignatedInitOverrideInfo {
423+
GenericSignature GenericSig;
424+
GenericParamList *GenericParams;
425+
SubstitutionMap OverrideSubMap;
426+
};
427+
}
428+
429+
static DesignatedInitOverrideInfo
430+
computeDesignatedInitOverrideSignature(ASTContext &ctx,
423431
ClassDecl *classDecl,
424432
Type superclassTy,
425433
ConstructorDecl *superclassCtor) {
426-
auto *superclassDecl = superclassTy->getAnyNominal();
427-
428434
auto *moduleDecl = classDecl->getParentModule();
429-
auto subMap = superclassTy->getContextSubstitutionMap(
430-
moduleDecl, superclassDecl);
431435

432-
GenericSignature genericSig;
433-
auto *genericParams = superclassCtor->getGenericParams();
436+
auto *superclassDecl = superclassTy->getAnyNominal();
434437

438+
auto classSig = classDecl->getGenericSignature();
435439
auto superclassCtorSig = superclassCtor->getGenericSignature();
436440
auto superclassSig = superclassDecl->getGenericSignature();
437441

442+
// These are our outputs.
443+
GenericSignature genericSig = classSig;
444+
auto *genericParams = superclassCtor->getGenericParams();
445+
auto subMap = superclassTy->getContextSubstitutionMap(
446+
moduleDecl, superclassDecl);
447+
438448
if (superclassCtorSig.getPointer() != superclassSig.getPointer()) {
449+
// If the base initiliazer's generic signature is different
450+
// from that of the base class, the base class initializer either
451+
// has generic parameters or a 'where' clause.
452+
//
453+
// We need to "rebase" the requirements on top of the derived class's
454+
// generic signature.
455+
439456
SmallVector<GenericTypeParamDecl *, 4> newParams;
440457
SmallVector<GenericTypeParamType *, 1> newParamTypes;
441458

442-
// Inheriting initializers that have their own generic parameters
459+
// If genericParams is non-null, the base class initializer has its own
460+
// generic parameters. Otherwise, it is non-generic with a contextual
461+
// 'where' clause.
443462
if (genericParams) {
444-
// First, clone the superclass constructor's generic parameter list,
463+
// First, clone the base class initializer's generic parameter list,
445464
// but change the depth of the generic parameters to be one greater
446465
// than the depth of the subclass.
447466
unsigned depth = 0;
@@ -457,8 +476,8 @@ configureGenericDesignatedInitOverride(ASTContext &ctx,
457476
newParams.push_back(newParam);
458477
}
459478

460-
// We don't have to clone the requirements, because they're not
461-
// used for anything.
479+
// We don't have to clone the RequirementReprs, because they're not
480+
// used for anything other than SIL mode.
462481
genericParams = GenericParamList::create(ctx,
463482
SourceLoc(),
464483
newParams,
@@ -473,7 +492,7 @@ configureGenericDesignatedInitOverride(ASTContext &ctx,
473492
}
474493
}
475494

476-
// Build a generic signature for the derived class initializer.
495+
// The depth at which the initializer's own generic parameters start, if any.
477496
unsigned superclassDepth = 0;
478497
if (superclassSig)
479498
superclassDepth = superclassSig->getGenericParams().back()->getDepth() + 1;
@@ -482,44 +501,52 @@ configureGenericDesignatedInitOverride(ASTContext &ctx,
482501
// initializer to form the requirements of the derived class initializer.
483502
auto substFn = [&](SubstitutableType *type) -> Type {
484503
auto *gp = cast<GenericTypeParamType>(type);
504+
// Generic parameters of the base class itself are mapped via the
505+
// substitution map of the superclass type.
485506
if (gp->getDepth() < superclassDepth)
486507
return Type(gp).subst(subMap);
508+
509+
// Generic parameters added by the base class initializer map to the new
510+
// generic parameters of the derived initializer.
487511
return genericParams->getParams()[gp->getIndex()]
488512
->getDeclaredInterfaceType();
489513
};
490514

491-
auto lookupConformanceFn =
492-
[&](CanType depTy, Type substTy,
493-
ProtocolDecl *proto) -> ProtocolConformanceRef {
494-
if (auto conf = subMap.lookupConformance(depTy, proto))
495-
return conf;
496-
497-
return ProtocolConformanceRef(proto);
498-
};
499-
500-
SmallVector<Requirement, 2> requirements;
501-
for (auto reqt : superclassCtorSig->getRequirements())
502-
if (auto substReqt = reqt.subst(substFn, lookupConformanceFn))
503-
requirements.push_back(*substReqt);
504-
505-
// Now form the substitution map that will be used to remap parameter
506-
// types.
507-
subMap = SubstitutionMap::get(superclassCtorSig,
508-
substFn, lookupConformanceFn);
509-
510-
genericSig = evaluateOrDefault(
511-
ctx.evaluator,
512-
AbstractGenericSignatureRequest{
513-
classDecl->getGenericSignature().getPointer(),
514-
std::move(newParamTypes),
515-
std::move(requirements)
516-
},
517-
GenericSignature());
518-
} else {
519-
genericSig = classDecl->getGenericSignature();
515+
// If we don't have any new generic parameters and the derived class is
516+
// not generic, the base class initializer's 'where' clause should already
517+
// be fully satisfied, and we can just drop it.
518+
if (genericParams != nullptr || classSig) {
519+
auto lookupConformanceFn =
520+
[&](CanType depTy, Type substTy,
521+
ProtocolDecl *proto) -> ProtocolConformanceRef {
522+
if (auto conf = subMap.lookupConformance(depTy, proto))
523+
return conf;
524+
525+
return ProtocolConformanceRef(proto);
526+
};
527+
528+
SmallVector<Requirement, 2> requirements;
529+
for (auto reqt : superclassCtorSig->getRequirements())
530+
if (auto substReqt = reqt.subst(substFn, lookupConformanceFn))
531+
requirements.push_back(*substReqt);
532+
533+
// Now form the substitution map that will be used to remap parameter
534+
// types.
535+
subMap = SubstitutionMap::get(superclassCtorSig,
536+
substFn, lookupConformanceFn);
537+
538+
genericSig = evaluateOrDefault(
539+
ctx.evaluator,
540+
AbstractGenericSignatureRequest{
541+
classSig.getPointer(),
542+
std::move(newParamTypes),
543+
std::move(requirements)
544+
},
545+
GenericSignature());
546+
}
520547
}
521548

522-
return std::make_tuple(genericSig, genericParams, subMap);
549+
return DesignatedInitOverrideInfo{genericSig, genericParams, subMap};
523550
}
524551

525552
static void
@@ -702,17 +729,33 @@ createDesignatedInitOverride(ClassDecl *classDecl,
702729
return nullptr;
703730
}
704731

705-
GenericSignature genericSig;
706-
GenericParamList *genericParams;
707-
SubstitutionMap subMap;
708-
709-
std::tie(genericSig, genericParams, subMap) =
710-
configureGenericDesignatedInitOverride(ctx,
732+
auto overrideInfo =
733+
computeDesignatedInitOverrideSignature(ctx,
711734
classDecl,
712735
superclassTy,
713736
superclassCtor);
714737

715-
// Determine the initializer parameters.
738+
if (auto superclassCtorSig = superclassCtor->getGenericSignature()) {
739+
auto *genericEnv = (overrideInfo.GenericSig
740+
? overrideInfo.GenericSig->getGenericEnvironment()
741+
: nullptr);
742+
743+
// If the base class initializer has a 'where' clause, it might impose
744+
// requirements on the base class's own generic parameters that are not
745+
// satisfied by the derived class. In this case, we don't want to inherit
746+
// this initializer; there's no way to call it on the derived class.
747+
auto checkResult = TypeChecker::checkGenericArguments(
748+
superclassCtor, SourceLoc(), SourceLoc(), Type(),
749+
superclassCtorSig->getGenericParams(),
750+
superclassCtorSig->getRequirements(),
751+
[&](Type type) -> Type {
752+
auto substType = type.subst(overrideInfo.OverrideSubMap);
753+
return GenericEnvironment::mapTypeIntoContext(
754+
genericEnv, substType);
755+
});
756+
if (checkResult != RequirementCheckResult::Success)
757+
return nullptr;
758+
}
716759

717760
// Create the initializer parameter patterns.
718761
OptionSet<ParameterList::CloneFlags> options
@@ -732,7 +775,7 @@ createDesignatedInitOverride(ClassDecl *classDecl,
732775
auto *bodyParam = bodyParams->get(idx);
733776

734777
auto paramTy = superclassParam->getInterfaceType();
735-
auto substTy = paramTy.subst(subMap);
778+
auto substTy = paramTy.subst(overrideInfo.OverrideSubMap);
736779

737780
bodyParam->setInterfaceType(substTy);
738781
}
@@ -747,12 +790,13 @@ createDesignatedInitOverride(ClassDecl *classDecl,
747790
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
748791
/*Throws=*/superclassCtor->hasThrows(),
749792
/*ThrowsLoc=*/SourceLoc(),
750-
bodyParams, genericParams, classDecl);
793+
bodyParams, overrideInfo.GenericParams,
794+
classDecl);
751795

752796
ctor->setImplicit();
753797

754798
// Set the interface type of the initializer.
755-
ctor->setGenericSignature(genericSig);
799+
ctor->setGenericSignature(overrideInfo.GenericSig);
756800

757801
ctor->setImplicitlyUnwrappedOptional(
758802
superclassCtor->isImplicitlyUnwrappedOptional());

test/SILGen/designated_init_inheritance_with_where_clause.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,32 @@ public class Pony<U : Ungulate> : Horse<U> {
2020
// CHECK-LABEL: sil [serialized] [exact_self_class] [ossa] @$s45designated_init_inheritance_with_where_clause4PonyCACyxGycAA12DomesticatedRzrlufC : $@convention(method) <U where U : Domesticated, U : Ungulate> (@thick Pony<U>.Type) -> @owned Pony<U> {
2121
// CHECK-LABEL: sil [ossa] @$s45designated_init_inheritance_with_where_clause4PonyCACyxGycAA12DomesticatedRzrlufc : $@convention(method) <U where U : Domesticated, U : Ungulate> (@owned Pony<U>) -> @owned Pony<U> {
2222
}
23+
24+
public class Barn<T> {
25+
init(_: T) where T : AnyObject {}
26+
init<U>(_: T, _: U) where T : Domesticated, U : Ungulate {}
27+
}
28+
29+
public class BigBarn : Barn<AnyObject> {
30+
// CHECK-LABEL: sil hidden [ossa] @$s45designated_init_inheritance_with_where_clause7BigBarnCyACyXlcfc : $@convention(method) (@owned AnyObject, @owned BigBarn) -> @owned BigBarn {
31+
}
32+
33+
public struct Cat : Domesticated {}
34+
public struct Sheep : Ungulate {}
35+
36+
public class SmallBarn : Barn<Cat> {
37+
// CHECK-LABEL: sil hidden [ossa] @$s45designated_init_inheritance_with_where_clause9SmallBarnCyAcA3CatV_xtcAA8UngulateRzlufc : $@convention(method) <U where U : Ungulate> (Cat, @in U, @owned SmallBarn) -> @owned SmallBarn {
38+
// CHECK-LABEL: sil private [thunk] [ossa] @$s45designated_init_inheritance_with_where_clause9SmallBarnCyAcA3CatV_xtcAA8UngulateRzlufCAA0H0CyAHyxGx_qd__tcAA12DomesticatedRzAaFRd__lufCTV : $@convention(method) <τ_0_0 where τ_0_0 : Ungulate> (@in Cat, @in τ_0_0, @thick SmallBarn.Type) -> @owned SmallBarn {
39+
}
40+
41+
// CHECK-LABEL: sil_vtable [serialized] BigBarn {
42+
// CHECK-NEXT: #Barn.init!allocator: <T where T : AnyObject> (Barn<T>.Type) -> (T) -> Barn<T> : @$s45designated_init_inheritance_with_where_clause7BigBarnCyACyXlcfC [override] // BigBarn.__allocating_init(_:)
43+
// CHECK-NEXT: #Barn.init!allocator: <T where T : Domesticated><U where U : Ungulate> (Barn<T>.Type) -> (T, U) -> Barn<T> : @$s45designated_init_inheritance_with_where_clause4BarnCyACyxGx_qd__tcAA12DomesticatedRzAA8UngulateRd__lufC [inherited] // Barn.__allocating_init<A>(_:_:)
44+
// CHECK-NEXT: #BigBarn.deinit!deallocator: @$s45designated_init_inheritance_with_where_clause7BigBarnCfD // BigBarn.__deallocating_deinit
45+
// CHECK-NEXT: }
46+
47+
// CHECK-LABEL: sil_vtable [serialized] SmallBarn {
48+
// CHECK-NEXT: #Barn.init!allocator: <T where T : AnyObject> (Barn<T>.Type) -> (T) -> Barn<T> : @$s45designated_init_inheritance_with_where_clause4BarnCyACyxGxcRlzClufC [inherited] // Barn.__allocating_init<A>(_:)
49+
// CHECK-NEXT: <T where T : Domesticated><U where U : Ungulate> (Barn<T>.Type) -> (T, U) -> Barn<T> : @$s45designated_init_inheritance_with_where_clause9SmallBarnCyAcA3CatV_xtcAA8UngulateRzlufCAA0H0CyAHyxGx_qd__tcAA12DomesticatedRzAaFRd__lufCTV [override] // vtable thunk for Barn.__allocating_init<A>(_:_:) dispatching to SmallBarn.__allocating_init<A>(_:_:)
50+
// CHECK-NEXT: #SmallBarn.deinit!deallocator: @$s45designated_init_inheritance_with_where_clause9SmallBarnCfD // SmallBarn.__deallocating_deinit
51+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)