Skip to content

Commit f0722bd

Browse files
Merge pull request swiftlang#36251 from AnthonyLatsis/super-dyn-self-propagation
Sema: Fix dynamic Self behavior for a «super» base expression
2 parents 6650feb + 79c0d93 commit f0722bd

File tree

10 files changed

+368
-163
lines changed

10 files changed

+368
-163
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3873,12 +3873,13 @@ class ConstraintSystem {
38733873
/// \param UseDC The context of the access. Some variables have different
38743874
/// types depending on where they are used.
38753875
///
3876-
/// \param base The optional base expression of this value reference
3876+
/// \param memberLocator The locator anchored at this value reference, when
3877+
/// it is a member reference.
38773878
///
38783879
/// \param wantInterfaceType Whether we want the interface type, if available.
38793880
Type getUnopenedTypeOfReference(VarDecl *value, Type baseType,
38803881
DeclContext *UseDC,
3881-
const DeclRefExpr *base = nullptr,
3882+
ConstraintLocator *memberLocator = nullptr,
38823883
bool wantInterfaceType = false);
38833884

38843885
/// Return the type-of-reference of the given value.
@@ -3889,15 +3890,16 @@ class ConstraintSystem {
38893890
/// \param UseDC The context of the access. Some variables have different
38903891
/// types depending on where they are used.
38913892
///
3892-
/// \param base The optional base expression of this value reference
3893+
/// \param memberLocator The locator anchored at this value reference, when
3894+
/// it is a member reference.
38933895
///
38943896
/// \param wantInterfaceType Whether we want the interface type, if available.
38953897
///
38963898
/// \param getType Optional callback to extract a type for given declaration.
38973899
static Type
38983900
getUnopenedTypeOfReference(VarDecl *value, Type baseType, DeclContext *UseDC,
38993901
llvm::function_ref<Type(VarDecl *)> getType,
3900-
const DeclRefExpr *base = nullptr,
3902+
ConstraintLocator *memberLocator = nullptr,
39013903
bool wantInterfaceType = false);
39023904

39033905
/// Retrieve the type of a reference to the given value declaration,
@@ -3916,8 +3918,7 @@ class ConstraintSystem {
39163918
Type baseTy, ValueDecl *decl, DeclContext *useDC,
39173919
bool isDynamicResult,
39183920
FunctionRefKind functionRefKind,
3919-
ConstraintLocatorBuilder locator,
3920-
const DeclRefExpr *base = nullptr,
3921+
ConstraintLocator *locator,
39213922
OpenedTypeMap *replacements = nullptr);
39223923

39233924
/// Retrieve a list of generic parameter types solver has "opened" (replaced
@@ -4018,7 +4019,8 @@ class ConstraintSystem {
40184019
ConstraintLocatorBuilder locator);
40194020

40204021
/// Retrieve the type that will be used when matching the given overload.
4021-
Type getEffectiveOverloadType(const OverloadChoice &overload,
4022+
Type getEffectiveOverloadType(ConstraintLocator *locator,
4023+
const OverloadChoice &overload,
40224024
bool allowMembers,
40234025
DeclContext *useDC);
40244026

@@ -5281,6 +5283,14 @@ Type isRawRepresentable(ConstraintSystem &cs, Type type);
52815283
Type isRawRepresentable(ConstraintSystem &cs, Type type,
52825284
KnownProtocolKind rawRepresentableProtocol);
52835285

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+
52845294
class DisjunctionChoice {
52855295
ConstraintSystem &CS;
52865296
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/CSGen.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ namespace {
464464
return;
465465
}
466466

467-
Type overloadType =
468-
CS.getEffectiveOverloadType(constraint->getOverloadChoice(),
469-
/*allowMembers=*/true, CS.DC);
467+
Type overloadType = CS.getEffectiveOverloadType(
468+
constraint->getLocator(), constraint->getOverloadChoice(),
469+
/*allowMembers=*/true, CS.DC);
470470
if (!overloadType)
471471
continue;
472472

@@ -489,9 +489,9 @@ namespace {
489489
// result type.
490490
if (numFavoredConstraints == 1) {
491491
auto overloadChoice = firstFavored->getOverloadChoice();
492-
auto overloadType =
493-
CS.getEffectiveOverloadType(overloadChoice, /*allowMembers=*/true,
494-
CS.DC);
492+
auto overloadType = CS.getEffectiveOverloadType(
493+
firstFavored->getLocator(), overloadChoice, /*allowMembers=*/true,
494+
CS.DC);
495495
auto resultType = overloadType->castTo<AnyFunctionType>()->getResult();
496496
if (!resultType->hasTypeParameter())
497497
CS.setFavoredType(expr, resultType.getPointer());

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9282,9 +9282,9 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl(
92829282
}
92839283

92849284
// Determine the type that this choice will have.
9285-
Type choiceType =
9286-
getEffectiveOverloadType(choice, /*allowMembers=*/true,
9287-
constraint->getOverloadUseDC());
9285+
Type choiceType = getEffectiveOverloadType(
9286+
constraint->getLocator(), choice, /*allowMembers=*/true,
9287+
constraint->getOverloadUseDC());
92889288
if (!choiceType) {
92899289
hasUnhandledConstraints = true;
92909290
return true;

lib/Sema/CSStep.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,9 @@ bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
662662
auto *decl = constraint->getOverloadChoice().getDecl();
663663
if (decl->getBaseIdentifier().isArithmeticOperator()) {
664664
auto *useDC = constraint->getOverloadUseDC();
665-
auto choiceType = CS.getEffectiveOverloadType(constraint->getOverloadChoice(),
666-
/*allowMembers=*/true, useDC);
665+
auto choiceType = CS.getEffectiveOverloadType(
666+
constraint->getLocator(), constraint->getOverloadChoice(),
667+
/*allowMembers=*/true, useDC);
667668
auto choiceFnType = choiceType->getAs<FunctionType>();
668669
auto genericFnType = decl->getInterfaceType()->getAs<GenericFunctionType>();
669670
auto signature = genericFnType->getGenericSignature();

0 commit comments

Comments
 (0)