Skip to content

Commit 79c0d93

Browse files
committed
Sema: Fix dynamic Self behavior for a «super» base expression
1 parent 8242d84 commit 79c0d93

File tree

6 files changed

+312
-100
lines changed

6 files changed

+312
-100
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5283,6 +5283,14 @@ Type isRawRepresentable(ConstraintSystem &cs, Type type);
52835283
Type isRawRepresentable(ConstraintSystem &cs, Type type,
52845284
KnownProtocolKind rawRepresentableProtocol);
52855285

5286+
/// Compute the type that shall stand in for dynamic 'Self' in a member
5287+
/// reference with a base of the given object type.
5288+
///
5289+
/// \param memberLocator The locator of the member constraint; used to retrieve
5290+
/// the expression that the locator is anchored to.
5291+
Type getDynamicSelfReplacementType(Type baseObjTy, const ValueDecl *member,
5292+
ConstraintLocator *memberLocator);
5293+
52865294
class DisjunctionChoice {
52875295
ConstraintSystem &CS;
52885296
unsigned Index;

lib/Sema/CSApply.cpp

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,8 +1285,8 @@ namespace {
12851285
ConstraintLocatorBuilder locator,
12861286
ConstraintLocatorBuilder memberLocator, bool Implicit,
12871287
AccessSemantics semantics) {
1288-
auto choice = overload.choice;
1289-
auto openedType = overload.openedType;
1288+
const auto &choice = overload.choice;
1289+
const auto openedType = overload.openedType;
12901290

12911291
ValueDecl *member = choice.getDecl();
12921292

@@ -1369,9 +1369,10 @@ namespace {
13691369
return forceUnwrapIfExpected(DSBI, choice, memberLocator);
13701370
}
13711371

1372-
bool isUnboundInstanceMember =
1373-
(!baseIsInstance && member->isInstanceMember());
1374-
bool isPartialApplication = shouldBuildCurryThunk(choice, baseIsInstance);
1372+
const bool isUnboundInstanceMember =
1373+
(!baseIsInstance && member->isInstanceMember());
1374+
const bool isPartialApplication =
1375+
shouldBuildCurryThunk(choice, baseIsInstance);
13751376

13761377
// The formal type of the 'self' value for the member's declaration.
13771378
Type containerTy = getBaseType(refTy->castTo<FunctionType>());
@@ -1531,8 +1532,8 @@ namespace {
15311532
base->setImplicit();
15321533
}
15331534

1534-
auto hasDynamicSelf =
1535-
varDecl->getValueInterfaceType()->hasDynamicSelfType();
1535+
const auto hasDynamicSelf =
1536+
varDecl->getValueInterfaceType()->hasDynamicSelfType();
15361537

15371538
auto memberRefExpr
15381539
= new (context) MemberRefExpr(base, dotLoc, memberRef,
@@ -1546,11 +1547,15 @@ namespace {
15461547
Expr *result = memberRefExpr;
15471548
closeExistential(result, locator);
15481549

1550+
// If the property is of dynamic 'Self' type, wrap an implicit
1551+
// conversion around the resulting expression, with the destination
1552+
// type having 'Self' swapped for the appropriate replacement
1553+
// type -- usually the base object type.
15491554
if (hasDynamicSelf) {
1550-
if (!baseTy->isEqual(containerTy)) {
1551-
result = new (context) CovariantReturnConversionExpr(
1552-
result, simplifyType(openedType));
1553-
cs.cacheType(result);
1555+
const auto conversionTy = simplifyType(openedType);
1556+
if (!containerTy->isEqual(conversionTy)) {
1557+
result = cs.cacheType(new (context) CovariantReturnConversionExpr(
1558+
result, conversionTy));
15541559
}
15551560
}
15561561
return forceUnwrapIfExpected(result, choice, memberLocator);
@@ -1567,9 +1572,8 @@ namespace {
15671572
cs.setType(declRefExpr, refTy);
15681573
Expr *ref = declRefExpr;
15691574

1570-
if (isPartialApplication) {
1571-
auto curryThunkTy = refTy->castTo<FunctionType>();
1572-
1575+
const auto isSuperPartialApplication = isPartialApplication && isSuper;
1576+
if (isSuperPartialApplication) {
15731577
// A partial application thunk consists of two nested closures:
15741578
//
15751579
// { self in { args... in self.method(args...) } }
@@ -1588,17 +1592,12 @@ namespace {
15881592
// very specific shape, we only emit a single closure here and
15891593
// capture the original SuperRefExpr, since its evaluation does not
15901594
// have side effects, instead of abstracting out a 'self' parameter.
1591-
if (isSuper) {
1592-
auto selfFnTy = curryThunkTy->getResult()->castTo<FunctionType>();
1593-
1594-
auto closure = buildCurryThunk(member, selfFnTy, base, ref,
1595-
memberLocator);
1595+
const auto selfFnTy =
1596+
refTy->castTo<FunctionType>()->getResult()->castTo<FunctionType>();
15961597

1597-
// Skip the code below -- we're not building an extra level of
1598-
// call by applying the 'super', instead the closure we just
1599-
// built is the curried reference.
1600-
return closure;
1601-
}
1598+
ref = buildCurryThunk(member, selfFnTy, base, ref, memberLocator);
1599+
} else if (isPartialApplication) {
1600+
auto curryThunkTy = refTy->castTo<FunctionType>();
16021601

16031602
// Another case where we want to build a single closure is when
16041603
// we have a partial application of a constructor on a statically-
@@ -1618,7 +1617,7 @@ namespace {
16181617
memberLocator);
16191618

16201619
// Skip the code below -- we're not building an extra level of
1621-
// call by applying the metatype instead the closure we just
1620+
// call by applying the metatype; instead, the closure we just
16221621
// built is the curried reference.
16231622
return closure;
16241623
}
@@ -1695,22 +1694,41 @@ namespace {
16951694
ref = outerClosure;
16961695
}
16971696

1698-
// If this is a method whose result type is dynamic Self, or a
1699-
// construction, replace the result type with the actual object type.
1697+
// If the member is a method with a dynamic 'Self' result type, wrap an
1698+
// implicit function type conversion around the resulting expression,
1699+
// with the destination type having 'Self' swapped for the appropriate
1700+
// replacement type -- usually the base object type.
17001701
if (!member->getDeclContext()->getSelfProtocolDecl()) {
17011702
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
17021703
if (func->hasDynamicSelfResult() &&
17031704
!baseTy->getOptionalObjectType()) {
1704-
if (!baseTy->isEqual(containerTy)) {
1705-
auto dynamicSelfFnType = refTy->replaceCovariantResultType(baseTy, 2);
1706-
ref = new (context) CovariantFunctionConversionExpr(ref,
1707-
dynamicSelfFnType);
1708-
cs.cacheType(ref);
1705+
// FIXME: Once CovariantReturnConversionExpr (unchecked_ref_cast)
1706+
// supports a class existential dest., consider using the opened
1707+
// type directly to avoid recomputing the 'Self' replacement and
1708+
// substituting.
1709+
const Type replacementTy = getDynamicSelfReplacementType(
1710+
baseTy, member, memberLocator.getBaseLocator());
1711+
if (!replacementTy->isEqual(containerTy)) {
1712+
Type conversionTy =
1713+
refTy->replaceCovariantResultType(replacementTy, 2);
1714+
if (isSuperPartialApplication) {
1715+
conversionTy =
1716+
conversionTy->castTo<FunctionType>()->getResult();
1717+
}
1718+
1719+
ref = cs.cacheType(new (context) CovariantFunctionConversionExpr(
1720+
ref, conversionTy));
17091721
}
17101722
}
17111723
}
17121724
}
17131725

1726+
// The thunk that is built for a 'super' method reference does not
1727+
// require application.
1728+
if (isSuperPartialApplication) {
1729+
return forceUnwrapIfExpected(ref, choice, memberLocator);
1730+
}
1731+
17141732
ApplyExpr *apply;
17151733
if (isa<ConstructorDecl>(member)) {
17161734
// FIXME: Provide type annotation.
@@ -2113,22 +2131,35 @@ namespace {
21132131
if (!base)
21142132
return nullptr;
21152133

2134+
const auto hasDynamicSelf =
2135+
subscript->getElementInterfaceType()->hasDynamicSelfType();
2136+
21162137
// Form the subscript expression.
21172138
auto subscriptExpr = SubscriptExpr::create(
21182139
ctx, base, index, subscriptRef, isImplicit, semantics, getType);
21192140
cs.setType(subscriptExpr, fullSubscriptTy->getResult());
21202141
subscriptExpr->setIsSuper(isSuper);
2142+
cs.setType(subscriptExpr,
2143+
hasDynamicSelf
2144+
? fullSubscriptTy->getResult()->replaceCovariantResultType(
2145+
containerTy, 0)
2146+
: fullSubscriptTy->getResult());
21212147

21222148
Expr *result = subscriptExpr;
21232149
closeExistential(result, locator);
21242150

2125-
if (subscript->getElementInterfaceType()->hasDynamicSelfType()) {
2126-
auto dynamicSelfFnType =
2127-
openedFullFnType->replaceCovariantResultType(baseTy, 2);
2128-
result =
2129-
new (ctx) CovariantReturnConversionExpr(result, dynamicSelfFnType);
2130-
cs.cacheType(result);
2131-
cs.setType(result, simplifyType(baseTy));
2151+
// If the element is of dynamic 'Self' type, wrap an implicit conversion
2152+
// around the resulting expression, with the destination type having
2153+
// 'Self' swapped for the appropriate replacement type -- usually the
2154+
// base object type.
2155+
if (hasDynamicSelf) {
2156+
const auto conversionTy = simplifyType(
2157+
selected.openedType->castTo<FunctionType>()->getResult());
2158+
2159+
if (!containerTy->isEqual(conversionTy)) {
2160+
result = cs.cacheType(
2161+
new (ctx) CovariantReturnConversionExpr(result, conversionTy));
2162+
}
21322163
}
21332164

21342165
return result;

lib/Sema/ConstraintSystem.cpp

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,36 @@ static bool isRequirementOrWitness(const ConstraintLocatorBuilder &locator) {
15141514
return false;
15151515
}
15161516

1517+
Type constraints::getDynamicSelfReplacementType(
1518+
Type baseObjTy, const ValueDecl *member, ConstraintLocator *memberLocator) {
1519+
// Constructions must always have their dynamic 'Self' result type replaced
1520+
// with the base object type, 'super' or not.
1521+
if (isa<ConstructorDecl>(member))
1522+
return baseObjTy;
1523+
1524+
const SuperRefExpr *SuperExpr = nullptr;
1525+
if (auto *E = getAsExpr(memberLocator->getAnchor())) {
1526+
if (auto *LE = dyn_cast<LookupExpr>(E)) {
1527+
SuperExpr = dyn_cast<SuperRefExpr>(LE->getBase());
1528+
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(E)) {
1529+
SuperExpr = dyn_cast<SuperRefExpr>(UDE->getBase());
1530+
}
1531+
}
1532+
1533+
// For anything else that isn't 'super', we want it to be the base
1534+
// object type.
1535+
if (!SuperExpr)
1536+
return baseObjTy;
1537+
1538+
// 'super' is special in that we actually want dynamic 'Self' to behave
1539+
// as if the base were 'self'.
1540+
const auto *selfDecl = SuperExpr->getSelf();
1541+
return selfDecl->getDeclContext()
1542+
->getInnermostTypeContext()
1543+
->mapTypeIntoContext(selfDecl->getInterfaceType())
1544+
->getMetatypeInstanceType();
1545+
}
1546+
15171547
std::pair<Type, Type>
15181548
ConstraintSystem::getTypeOfMemberReference(
15191549
Type baseTy, ValueDecl *value, DeclContext *useDC,
@@ -1712,21 +1742,23 @@ ConstraintSystem::getTypeOfMemberReference(
17121742
// Compute the type of the reference.
17131743
Type type = openedType;
17141744

1745+
// Cope with dynamic 'Self'.
17151746
if (!outerDC->getSelfProtocolDecl()) {
1716-
// Class methods returning Self as well as constructors get the
1717-
// result replaced with the base object type.
1747+
const auto replacementTy =
1748+
getDynamicSelfReplacementType(baseObjTy, value, locator);
1749+
17181750
if (auto func = dyn_cast<AbstractFunctionDecl>(value)) {
17191751
if (func->hasDynamicSelfResult() &&
17201752
!baseObjTy->getOptionalObjectType()) {
1721-
type = type->replaceCovariantResultType(baseObjTy, 2);
1753+
type = type->replaceCovariantResultType(replacementTy, 2);
17221754
}
17231755
} else if (auto *decl = dyn_cast<SubscriptDecl>(value)) {
17241756
if (decl->getElementInterfaceType()->hasDynamicSelfType()) {
1725-
type = type->replaceCovariantResultType(baseObjTy, 2);
1757+
type = type->replaceCovariantResultType(replacementTy, 2);
17261758
}
17271759
} else if (auto *decl = dyn_cast<VarDecl>(value)) {
17281760
if (decl->getValueInterfaceType()->hasDynamicSelfType()) {
1729-
type = type->replaceCovariantResultType(baseObjTy, 1);
1761+
type = type->replaceCovariantResultType(replacementTy, 1);
17301762
}
17311763
}
17321764
}
@@ -1795,7 +1827,8 @@ ConstraintSystem::getTypeOfMemberReference(
17951827
return { openedType, type };
17961828
}
17971829

1798-
Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload,
1830+
Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
1831+
const OverloadChoice &overload,
17991832
bool allowMembers,
18001833
DeclContext *useDC) {
18011834
switch (overload.getKind()) {
@@ -1854,15 +1887,26 @@ Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload,
18541887
if (!allowMembers)
18551888
return Type();
18561889

1890+
const auto withDynamicSelfResultReplaced = [&](Type type,
1891+
unsigned uncurryLevel) {
1892+
const Type baseObjTy = overload.getBaseType()
1893+
->getRValueType()
1894+
->getMetatypeInstanceType()
1895+
->lookThroughAllOptionalTypes();
1896+
1897+
return type->replaceCovariantResultType(
1898+
getDynamicSelfReplacementType(baseObjTy, decl, locator),
1899+
uncurryLevel);
1900+
};
1901+
18571902
if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
18581903
auto elementTy = subscript->getElementInterfaceType();
18591904

18601905
if (doesStorageProduceLValue(subscript, overload.getBaseType(), useDC))
18611906
elementTy = LValueType::get(elementTy);
18621907
else if (elementTy->hasDynamicSelfType()) {
1863-
Type selfType = overload.getBaseType()->getRValueType()
1864-
->getMetatypeInstanceType()->lookThroughAllOptionalTypes();
1865-
elementTy = elementTy->replaceCovariantResultType(selfType, 0);
1908+
elementTy = withDynamicSelfResultReplaced(elementTy,
1909+
/*uncurryLevel=*/0);
18661910
}
18671911

18681912
// See ConstraintSystem::resolveOverload() -- optional and dynamic
@@ -1876,8 +1920,11 @@ Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload,
18761920
type = FunctionType::get(indices, elementTy);
18771921
} else if (auto var = dyn_cast<VarDecl>(decl)) {
18781922
type = var->getValueInterfaceType();
1879-
if (doesStorageProduceLValue(var, overload.getBaseType(), useDC))
1923+
if (doesStorageProduceLValue(var, overload.getBaseType(), useDC)) {
18801924
type = LValueType::get(type);
1925+
} else if (type->hasDynamicSelfType()) {
1926+
type = withDynamicSelfResultReplaced(type, /*uncurryLevel=*/0);
1927+
}
18811928
} else if (isa<AbstractFunctionDecl>(decl) || isa<EnumElementDecl>(decl)) {
18821929
if (decl->isInstanceMember() &&
18831930
(!overload.getBaseType() ||
@@ -1892,18 +1939,16 @@ Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload,
18921939
return Type();
18931940

18941941
if (!overload.getBaseType()->getOptionalObjectType()) {
1895-
Type selfType = overload.getBaseType()
1896-
->getRValueType()
1897-
->getMetatypeInstanceType();
1898-
18991942
// `Int??(0)` if we look through all optional types for `Self`
19001943
// we'll end up with incorrect type `Int?` for result because
19011944
// the actual result type is `Int??`.
1902-
if (isa<ConstructorDecl>(decl) && selfType->getOptionalObjectType())
1945+
if (isa<ConstructorDecl>(decl) && overload.getBaseType()
1946+
->getRValueType()
1947+
->getMetatypeInstanceType()
1948+
->getOptionalObjectType())
19031949
return Type();
19041950

1905-
type = type->replaceCovariantResultType(
1906-
selfType->lookThroughAllOptionalTypes(), 2);
1951+
type = withDynamicSelfResultReplaced(type, /*uncurryLevel=*/2);
19071952
}
19081953
}
19091954
}

0 commit comments

Comments
 (0)