Skip to content

Commit e2d81a1

Browse files
committed
Sema: Fix bug in buildMemberRef() with subclass existentials
Make sure we use the right 'self' type in various places. When calling a Self-returning class method on a subclass existential, the following has to happen correctly: - The existential is opened to produce an archetype with a superclass constraint. - The archetype is upcast to a class type to produce the 'self' parameter for the call. - The method call returns a value with the same type as the 'self' parameter. - The return value is downcast to the opened archetype. - The opened archetype is converted back to an existential. Some SILGen tests in an upcoming patch exercise this code path.
1 parent 9bd7929 commit e2d81a1

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

lib/Sema/CSApply.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ namespace {
752752

753753
bool isSuper = base->isSuperExpr();
754754

755+
// The formal type of the 'self' value for the call.
755756
Type baseTy = cs.getType(base)->getRValueType();
756757

757758
// Explicit member accesses are permitted to implicitly look
@@ -801,12 +802,15 @@ namespace {
801802
cs.getType(ref)));
802803
}
803804

804-
// Produce a reference to the type of the container the member
805-
// resides in.
805+
// The formal type of the 'self' value for the member's declaration.
806806
Type containerTy =
807807
refTy->castTo<FunctionType>()
808808
->getInput()->getRValueInstanceType();
809809

810+
// If we have an opened existential, selfTy and baseTy will both be
811+
// the same opened existential type.
812+
Type selfTy = containerTy;
813+
810814
// If we opened up an existential when referencing this member, update
811815
// the base accordingly.
812816
auto knownOpened = solution.OpenedExistentialTypes.find(
@@ -816,7 +820,7 @@ namespace {
816820
if (knownOpened != solution.OpenedExistentialTypes.end()) {
817821
base = openExistentialReference(base, knownOpened->second, member);
818822
baseTy = knownOpened->second;
819-
containerTy = baseTy;
823+
selfTy = baseTy;
820824
openedExistential = true;
821825
}
822826

@@ -852,17 +856,18 @@ namespace {
852856

853857
// If the base is already an lvalue with the right base type, we can
854858
// pass it as an inout qualified type.
855-
Type selfTy = containerTy;
859+
auto selfParamTy = selfTy;
860+
856861
if (selfTy->isEqual(baseTy))
857862
if (cs.getType(base)->is<LValueType>())
858-
selfTy = InOutType::get(selfTy);
863+
selfParamTy = InOutType::get(selfTy);
859864
base = coerceObjectArgumentToType(
860-
base, selfTy, member, semantics,
865+
base, selfParamTy, member, semantics,
861866
locator.withPathElement(ConstraintLocator::MemberRefBase));
862867
} else {
863868
// Convert the base to an rvalue of the appropriate metatype.
864869
base = coerceToType(base,
865-
MetatypeType::get(containerTy),
870+
MetatypeType::get(selfTy),
866871
locator.withPathElement(
867872
ConstraintLocator::MemberRefBase));
868873
if (!base)
@@ -6554,9 +6559,6 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
65546559
Expr *result = tc.substituteInputSugarTypeForResult(apply);
65556560
cs.cacheExprTypes(result);
65566561

6557-
// Try closing the existential, if there is one.
6558-
closeExistential(result, locator);
6559-
65606562
// If we have a covariant result type, perform the conversion now.
65616563
if (covariantResultType) {
65626564
if (covariantResultType->is<FunctionType>())
@@ -6567,6 +6569,9 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
65676569
result, covariantResultType));
65686570
}
65696571

6572+
// Try closing the existential, if there is one.
6573+
closeExistential(result, locator);
6574+
65706575
// Extract all arguments.
65716576
auto *CEA = arg;
65726577
if (auto *TSE = dyn_cast<TupleShuffleExpr>(CEA))

0 commit comments

Comments
 (0)