Skip to content

Commit 6752266

Browse files
authored
Merge pull request #7534 from jckarter/covariant-self-init-delegation
Sema: Type-check initializer delegation as a covariant expression.
2 parents 304d2be + 8fc40ba commit 6752266

File tree

8 files changed

+98
-9
lines changed

8 files changed

+98
-9
lines changed

lib/AST/Expr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,12 @@ RebindSelfInConstructorExpr::getCalledConstructor(bool &isChainToSuper) const {
18091809
continue;
18101810
}
18111811

1812+
// Look through covariant return expressions.
1813+
if (auto covariantExpr
1814+
= dyn_cast<CovariantReturnConversionExpr>(candidate)) {
1815+
candidate = covariantExpr->getSubExpr();
1816+
continue;
1817+
}
18121818
break;
18131819
}
18141820

lib/SILGen/SILGenPoly.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,19 @@ ManagedValue Transform::transform(ManagedValue v,
473473
v.getCleanup());
474474
}
475475

476-
// Upcast to a superclass.
477-
return ManagedValue(SGF.B.createUpcast(Loc,
478-
v.getValue(),
479-
loweredResultTy),
480-
v.getCleanup());
476+
if (outputSubstType->isExactSuperclassOf(inputSubstType, nullptr)) {
477+
// Upcast to a superclass.
478+
return ManagedValue(SGF.B.createUpcast(Loc,
479+
v.getValue(),
480+
loweredResultTy),
481+
v.getCleanup());
482+
} else {
483+
// Unchecked-downcast to a covariant return type.
484+
assert(inputSubstType->isExactSuperclassOf(outputSubstType, nullptr)
485+
&& "should be inheritance relationship between input and output");
486+
return SGF.emitManagedRValueWithCleanup(
487+
SGF.B.createUncheckedRefCast(Loc, v.forward(SGF), loweredResultTy));
488+
}
481489
}
482490

483491
// - upcasts from an archetype

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,8 +1129,13 @@ static bool isSelfInitUse(SILInstruction *I) {
11291129
LocExpr = TE->getSubExpr();
11301130
else if (auto *FVE = dyn_cast<ForceValueExpr>(LocExpr))
11311131
LocExpr = FVE->getSubExpr();
1132-
}
1132+
1133+
}
11331134

1135+
// Look through covariant return, if any.
1136+
if (auto CRE = dyn_cast<CovariantReturnConversionExpr>(LocExpr))
1137+
LocExpr = CRE->getSubExpr();
1138+
11341139
// This is a self.init call if structured like this:
11351140
//
11361141
// (call_expr type='SomeClass'

lib/Sema/CSApply.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,8 @@ namespace {
13651365

13661366
/// \brief Build a new reference to another constructor.
13671367
Expr *buildOtherConstructorRef(Type openedFullType,
1368-
ConstructorDecl *ctor, DeclNameLoc loc,
1368+
ConstructorDecl *ctor, Expr *base,
1369+
DeclNameLoc loc,
13691370
ConstraintLocatorBuilder locator,
13701371
bool implicit) {
13711372
auto &tc = cs.getTypeChecker();
@@ -1402,8 +1403,21 @@ namespace {
14021403
resultFnTy->getExtInfo());
14031404

14041405
// Build the constructor reference.
1405-
return cs.cacheType(
1406+
Expr *ctorRef = cs.cacheType(
14061407
new (ctx) OtherConstructorDeclRefExpr(ref, loc, implicit, resultTy));
1408+
1409+
// Wrap in covariant `Self` return if needed.
1410+
if (selfTy->hasReferenceSemantics()) {
1411+
auto covariantTy = resultTy
1412+
->replaceCovariantResultType(base->getType()
1413+
->getLValueOrInOutObjectType(),
1414+
ctor->getNumParameterLists());
1415+
if (!covariantTy->isEqual(resultTy))
1416+
ctorRef = cs.cacheType(
1417+
new (ctx) CovariantFunctionConversionExpr(ctorRef, covariantTy));
1418+
}
1419+
1420+
return ctorRef;
14071421
}
14081422

14091423
/// Bridge the given value (which is an error type) to NSError.
@@ -2458,7 +2472,7 @@ namespace {
24582472
}
24592473

24602474
// Build a partial application of the delegated initializer.
2461-
Expr *ctorRef = buildOtherConstructorRef(openedType, ctor, nameLoc,
2475+
Expr *ctorRef = buildOtherConstructorRef(openedType, ctor, base, nameLoc,
24622476
ctorLocator, implicit);
24632477
auto *call = new (cs.getASTContext()) DotSyntaxCallExpr(ctorRef, dotLoc,
24642478
base);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -emit-sil -verify %s
3+
4+
protocol BestFriend: class {
5+
init()
6+
static func create() -> Self
7+
}
8+
9+
class Animal {
10+
required init(species: String) {}
11+
12+
static func create() -> Self { return self.init() }
13+
required convenience init() { self.init(species: "\(type(of: self))") }
14+
}
15+
16+
class Dog: Animal, BestFriend {}
17+
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC4main3DogS_10BestFriendS_FS1_CfT_x
18+
// CHECK: [[SELF:%.*]] = apply
19+
// CHECK: unchecked_ref_cast [[SELF]] : $Animal to $Dog
20+
// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC4main3DogS_10BestFriendS_ZFS1_6createfT_x
21+
// CHECK: [[SELF:%.*]] = apply
22+
// CHECK: unchecked_ref_cast [[SELF]] : $Animal to $Dog
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__attribute__((objc_root_class))
2+
@interface MyObject
3+
@end
4+
5+
__attribute__((swift_name("MyObject.init(id:)")))
6+
MyObject *_Nonnull my_object_create(int id);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-swift-frontend -emit-sil -verify -import-objc-header %S/Inputs/c-func-member-init.h %s
2+
// REQUIRES: objc_interop
3+
4+
extension MyObject {
5+
convenience init() {
6+
self.init(id: 1738)
7+
}
8+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend -emit-sil -verify %s
2+
3+
class Animal {
4+
convenience init?(species: String) {
5+
self.init()
6+
}
7+
}
8+
9+
class Dog: Animal {
10+
var butt = "dog \("butt")"
11+
12+
convenience init(owner: String) {
13+
self.init(species: "Dog")!
14+
}
15+
16+
17+
}
18+
19+
print(Dog(owner: "John Arbuckle").butt)
20+

0 commit comments

Comments
 (0)