Skip to content

Commit f1207ff

Browse files
Merge pull request swiftlang#59171 from AnthonyLatsis/init-delegation-optional
CSGen, SILGen: Fix delegations to `Optional` initializers
2 parents 4f6cce7 + 1842772 commit f1207ff

File tree

5 files changed

+778
-78
lines changed

5 files changed

+778
-78
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4166,23 +4166,31 @@ RValue RValueEmitter::visitRebindSelfInConstructorExpr(
41664166
auto ctorDecl = cast<ConstructorDecl>(selfDecl->getDeclContext());
41674167
auto selfIfaceTy = ctorDecl->getDeclContext()->getSelfInterfaceType();
41684168
auto selfTy = ctorDecl->mapTypeIntoContext(selfIfaceTy);
4169-
4170-
auto newSelfTy = E->getSubExpr()->getType();
4171-
bool outerIsOptional = false;
4172-
bool innerIsOptional = false;
4173-
auto objTy = newSelfTy->getOptionalObjectType();
4174-
if (objTy) {
4175-
outerIsOptional = true;
4176-
newSelfTy = objTy;
4177-
4178-
// "try? self.init()" can give us two levels of optional if the initializer
4179-
// we delegate to is failable.
4180-
objTy = newSelfTy->getOptionalObjectType();
4181-
if (objTy) {
4182-
innerIsOptional = true;
4183-
newSelfTy = objTy;
4169+
4170+
bool isChaining; // Ignored
4171+
auto *otherCtor = E->getCalledConstructor(isChaining)->getDecl();
4172+
assert(otherCtor);
4173+
4174+
auto getOptionalityDepth = [](Type ty) {
4175+
unsigned level = 0;
4176+
Type objTy = ty->getOptionalObjectType();
4177+
while (objTy) {
4178+
++level;
4179+
objTy = objTy->getOptionalObjectType();
41844180
}
4185-
}
4181+
4182+
return level;
4183+
};
4184+
4185+
// The optionality depth of the 'new self' value. This can be '2' if the ctor
4186+
// we are delegating/chaining to is both throwing and failable, or more if
4187+
// 'self' is optional.
4188+
auto srcOptionalityDepth = getOptionalityDepth(E->getSubExpr()->getType());
4189+
4190+
// The optionality depth of the result type of the enclosing initializer in
4191+
// this context.
4192+
const auto destOptionalityDepth = getOptionalityDepth(
4193+
ctorDecl->mapTypeIntoContext(ctorDecl->getResultInterfaceType()));
41864194

41874195
// The subexpression consumes the current 'self' binding.
41884196
assert(SGF.SelfInitDelegationState == SILGenFunction::NormalSelf
@@ -4199,13 +4207,25 @@ RValue RValueEmitter::visitRebindSelfInConstructorExpr(
41994207
SGF.emitAddressOfLocalVarDecl(E, selfDecl, selfTy->getCanonicalType(),
42004208
SGFAccessKind::Write).getLValueAddress();
42014209

4202-
// Handle a nested optional case (see above).
4203-
if (innerIsOptional)
4210+
// Flatten a nested optional if 'new self' is a deeper optional than we
4211+
// can return.
4212+
if (srcOptionalityDepth > destOptionalityDepth) {
4213+
assert(destOptionalityDepth > 0);
4214+
assert(otherCtor->isFailable() && otherCtor->hasThrows());
4215+
4216+
--srcOptionalityDepth;
42044217
newSelf = flattenOptional(SGF, E, newSelf);
42054218

4206-
// If both the delegated-to initializer and our enclosing initializer can
4207-
// fail, deal with the failure.
4208-
if (outerIsOptional && ctorDecl->isFailable()) {
4219+
assert(srcOptionalityDepth == destOptionalityDepth &&
4220+
"Flattening a single level was not enough?");
4221+
}
4222+
4223+
// If the enclosing ctor is failable and the optionality depths match, switch
4224+
// on 'new self' to either return 'nil' or continue with the projected value.
4225+
if (srcOptionalityDepth == destOptionalityDepth && ctorDecl->isFailable()) {
4226+
assert(destOptionalityDepth > 0);
4227+
assert(otherCtor->isFailable() || otherCtor->hasThrows());
4228+
42094229
SILBasicBlock *someBB = SGF.createBasicBlock();
42104230

42114231
auto hasValue = SGF.emitDoesOptionalHaveValue(E, newSelf.getValue());
@@ -4224,7 +4244,7 @@ RValue RValueEmitter::visitRebindSelfInConstructorExpr(
42244244
SGF.getTypeLowering(newSelf.getType()),
42254245
SGFContext());
42264246
}
4227-
4247+
42284248
// If we called a constructor that requires a downcast, perform the downcast.
42294249
auto destTy = SGF.getLoweredType(selfTy);
42304250
if (newSelf.getType() != destTy) {

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,23 +2237,18 @@ namespace {
22372237

22382238
// The constructor was opened with the allocating type, not the
22392239
// initializer type. Map the former into the latter.
2240-
auto resultTy = solution.simplifyType(openedFullType);
2240+
auto *resultTy =
2241+
solution.simplifyType(openedFullType)->castTo<FunctionType>();
22412242

2242-
auto selfTy = getBaseType(resultTy->castTo<FunctionType>());
2243-
2244-
// Also replace the result type with the base type, so that calls
2245-
// to constructors defined in a superclass will know to cast the
2246-
// result to the derived type.
2247-
resultTy = resultTy->replaceCovariantResultType(selfTy, 2);
2243+
const auto selfTy = getBaseType(resultTy);
22482244

22492245
ParameterTypeFlags flags;
22502246
if (!selfTy->hasReferenceSemantics())
22512247
flags = flags.withInOut(true);
22522248

22532249
auto selfParam = AnyFunctionType::Param(selfTy, Identifier(), flags);
2254-
resultTy = FunctionType::get({selfParam},
2255-
resultTy->castTo<FunctionType>()->getResult(),
2256-
resultTy->castTo<FunctionType>()->getExtInfo());
2250+
resultTy = FunctionType::get({selfParam}, resultTy->getResult(),
2251+
resultTy->getExtInfo());
22572252

22582253
// Build the constructor reference.
22592254
Expr *ctorRef = cs.cacheType(

lib/Sema/CSGen.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,9 +1700,48 @@ namespace {
17001700
if (!optTy)
17011701
return Type();
17021702

1703-
// Prior to Swift 5, 'try?' always adds an additional layer of optionality,
1704-
// even if the sub-expression was already optional.
1705-
if (CS.getASTContext().LangOpts.isSwiftVersionAtLeast(5)) {
1703+
bool isDelegationToOptionalInit = false;
1704+
{
1705+
Expr *e = expr->getSubExpr();
1706+
while (true) {
1707+
e = e->getSemanticsProvidingExpr();
1708+
1709+
// Look through force-value expressions.
1710+
if (auto *FVE = dyn_cast<ForceValueExpr>(e)) {
1711+
e = FVE->getSubExpr();
1712+
continue;
1713+
}
1714+
1715+
break;
1716+
}
1717+
1718+
if (auto *CE = dyn_cast<CallExpr>(e)) {
1719+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(CE->getFn())) {
1720+
if (!CS.getType(UDE->getBase())->is<AnyMetatypeType>()) {
1721+
auto overload =
1722+
CS.findSelectedOverloadFor(CS.getConstraintLocator(
1723+
UDE, ConstraintLocator::ConstructorMember));
1724+
if (overload) {
1725+
auto *decl = overload->choice.getDeclOrNull();
1726+
if (decl && isa<ConstructorDecl>(decl) &&
1727+
decl->getDeclContext()
1728+
->getSelfNominalTypeDecl()
1729+
->isOptionalDecl())
1730+
isDelegationToOptionalInit = true;
1731+
}
1732+
}
1733+
}
1734+
}
1735+
}
1736+
1737+
// Prior to Swift 5, 'try?' always adds an additional layer of
1738+
// optionality, even if the sub-expression was already optional.
1739+
//
1740+
// NB Keep adding the additional layer in Swift 5 and on if this 'try?'
1741+
// applies to a delegation to an 'Optional' initializer, or else we won't
1742+
// discern the difference between a failure and a constructed value.
1743+
if (CS.getASTContext().LangOpts.isSwiftVersionAtLeast(5) &&
1744+
!isDelegationToOptionalInit) {
17061745
CS.addConstraint(ConstraintKind::Conversion,
17071746
CS.getType(expr->getSubExpr()), optTy,
17081747
CS.getConstraintLocator(expr));

0 commit comments

Comments
 (0)