Skip to content

Commit 1a860cc

Browse files
committed
Sema: Simplify adjustSelfTypeForMember() a little bit to avoid a cycle
We used to wrap the base expression in an InOutExpr when accessing a computed property. This was a vestigial remnant of differences in the SILGen code paths for stored vs computed property access. These days SILGen doesn't care and is perfectly happy to call getters and setters with an LValueType base as well. This allows us to remove the call to getAccessSemantics(), which for a 'didSet', had to kick off type checking of the body. Fixes <rdar://problem/69532933>.
1 parent d5febdb commit 1a860cc

File tree

3 files changed

+48
-39
lines changed

3 files changed

+48
-39
lines changed

lib/AST/ASTVerifier.cpp

+17-17
Original file line numberDiff line numberDiff line change
@@ -1828,30 +1828,30 @@ class Verifier : public ASTWalker {
18281828
Out << "\n";
18291829
abort();
18301830
}
1831-
1831+
1832+
if (!isa<VarDecl>(E->getMember().getDecl())) {
1833+
Out << "Member reference to a non-VarDecl\n";
1834+
E->dump(Out);
1835+
Out << "\n";
1836+
abort();
1837+
}
1838+
1839+
auto baseType = E->getBase()->getType();
1840+
if (baseType->is<InOutType>()) {
1841+
Out << "Member reference to an inout type\n";
1842+
E->dump(Out);
1843+
Out << "\n";
1844+
abort();
1845+
}
1846+
18321847
// The base of a member reference cannot be an existential type.
1833-
if (E->getBase()->getType()->getWithoutSpecifierType()
1834-
->isExistentialType()) {
1848+
if (baseType->getWithoutSpecifierType()->isExistentialType()) {
18351849
Out << "Member reference into an unopened existential type\n";
18361850
E->dump(Out);
18371851
Out << "\n";
18381852
abort();
18391853
}
18401854

1841-
// The only time the base is allowed to be inout is if we are accessing
1842-
// a computed property or if the base is a protocol or existential.
1843-
if (auto *baseIOT = E->getBase()->getType()->getAs<InOutType>()) {
1844-
if (!baseIOT->getObjectType()->is<ArchetypeType>()) {
1845-
auto *VD = dyn_cast<VarDecl>(E->getMember().getDecl());
1846-
if (!VD || !VD->requiresOpaqueAccessors()) {
1847-
Out << "member_ref_expr on value of inout type\n";
1848-
E->dump(Out);
1849-
Out << "\n";
1850-
abort();
1851-
}
1852-
}
1853-
}
1854-
18551855
// FIXME: Check container/member types through substitutions.
18561856

18571857
verifyCheckedBase(E);

lib/Sema/CSApply.cpp

+12-22
Original file line numberDiff line numberDiff line change
@@ -6871,7 +6871,13 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
68716871
Type baseTy, ValueDecl *member,
68726872
AccessSemantics semantics,
68736873
DeclContext *UseDC) {
6874-
auto baseObjectTy = baseTy->getWithoutSpecifierType();
6874+
assert(!baseTy->is<LValueType>());
6875+
6876+
auto inOutTy = baseTy->getAs<InOutType>();
6877+
if (!inOutTy)
6878+
return baseTy;
6879+
6880+
auto baseObjectTy = inOutTy->getObjectType();
68756881

68766882
if (isa<ConstructorDecl>(member))
68776883
return baseObjectTy;
@@ -6880,7 +6886,7 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
68806886
// If 'self' is an inout type, turn the base type into an lvalue
68816887
// type with the same qualifiers.
68826888
if (func->isMutating())
6883-
return InOutType::get(baseObjectTy);
6889+
return baseTy;
68846890

68856891
// Otherwise, return the rvalue type.
68866892
return baseObjectTy;
@@ -6903,26 +6909,10 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
69036909
!isNonMutatingSetterPWAssignInsideInit(baseExpr, member, UseDC))
69046910
return baseObjectTy;
69056911

6906-
// If we're calling an accessor, keep the base as an inout type, because the
6907-
// getter may be mutating.
6908-
auto strategy = SD->getAccessStrategy(semantics,
6909-
isSettableFromHere
6910-
? AccessKind::ReadWrite
6911-
: AccessKind::Read,
6912-
UseDC->getParentModule(),
6913-
UseDC->getResilienceExpansion());
6914-
if (baseTy->is<InOutType>() && strategy.getKind() != AccessStrategy::Storage)
6915-
return InOutType::get(baseObjectTy);
6916-
6917-
// Accesses to non-function members in value types are done through an @lvalue
6918-
// type.
6919-
if (baseTy->is<InOutType>())
6920-
return LValueType::get(baseObjectTy);
6921-
6922-
// Accesses to members in values of reference type (classes, metatypes) are
6923-
// always done through a the reference to self. Accesses to value types with
6924-
// a non-mutable self are also done through the base type.
6925-
return baseTy;
6912+
if (isa<SubscriptDecl>(member))
6913+
return baseTy;
6914+
6915+
return LValueType::get(baseObjectTy);
69266916
}
69276917

69286918
Expr *

test/decl/var/didset_cycle.swift

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-swift-frontend -typecheck %s
2+
3+
func doSomething(_: Int) {}
4+
5+
struct S {
6+
var x: Int {
7+
didSet {
8+
doSomething(y)
9+
doSomething(self.y)
10+
}
11+
}
12+
13+
var y: Int {
14+
didSet {
15+
doSomething(x)
16+
doSomething(self.x)
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)