Skip to content

Commit 2fb3c7c

Browse files
authored
Merge pull request swiftlang#34092 from slavapestov/didset-access-semantics-cycle
Sema: Simplify adjustSelfTypeForMember() a little bit to avoid a cycle
2 parents f158e6a + 71a281c commit 2fb3c7c

File tree

5 files changed

+155
-76
lines changed

5 files changed

+155
-76
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

+25-41
Original file line numberDiff line numberDiff line change
@@ -1175,8 +1175,8 @@ namespace {
11751175
if (cs.getType(base)->is<LValueType>())
11761176
selfParamTy = InOutType::get(selfTy);
11771177

1178-
base = coerceObjectArgumentToType(
1179-
base, selfParamTy, member, semantics,
1178+
base = coerceSelfArgumentToType(
1179+
base, selfParamTy, member,
11801180
locator.withPathElement(ConstraintLocator::MemberRefBase));
11811181
} else {
11821182
if (!isExistentialMetatype || openedExistential) {
@@ -1589,7 +1589,7 @@ namespace {
15891589
ArrayRef<Identifier> argLabels,
15901590
ConstraintLocatorBuilder locator);
15911591

1592-
/// Coerce the given object argument (e.g., for the base of a
1592+
/// Coerce the given 'self' argument (e.g., for the base of a
15931593
/// member expression) to the given type.
15941594
///
15951595
/// \param expr The expression to coerce.
@@ -1598,13 +1598,10 @@ namespace {
15981598
///
15991599
/// \param member The member being accessed.
16001600
///
1601-
/// \param semantics The kind of access we've been asked to perform.
1602-
///
16031601
/// \param locator Locator used to describe where in this expression we are.
1604-
Expr *coerceObjectArgumentToType(Expr *expr,
1605-
Type baseTy, ValueDecl *member,
1606-
AccessSemantics semantics,
1607-
ConstraintLocatorBuilder locator);
1602+
Expr *coerceSelfArgumentToType(Expr *expr,
1603+
Type baseTy, ValueDecl *member,
1604+
ConstraintLocatorBuilder locator);
16081605

16091606
private:
16101607
/// Build a new subscript.
@@ -1808,8 +1805,7 @@ namespace {
18081805
// Handle dynamic lookup.
18091806
if (choice.getKind() == OverloadChoiceKind::DeclViaDynamic ||
18101807
subscript->getAttrs().hasAttribute<OptionalAttr>()) {
1811-
base = coerceObjectArgumentToType(base, baseTy, subscript,
1812-
AccessSemantics::Ordinary, locator);
1808+
base = coerceSelfArgumentToType(base, baseTy, subscript, locator);
18131809
if (!base)
18141810
return nullptr;
18151811

@@ -1833,8 +1829,8 @@ namespace {
18331829
auto containerTy = solution.simplifyType(openedBaseType);
18341830

18351831
if (baseIsInstance) {
1836-
base = coerceObjectArgumentToType(
1837-
base, containerTy, subscript, AccessSemantics::Ordinary,
1832+
base = coerceSelfArgumentToType(
1833+
base, containerTy, subscript,
18381834
locator.withPathElement(ConstraintLocator::MemberRefBase));
18391835
} else {
18401836
base = coerceToType(base,
@@ -6870,9 +6866,14 @@ static bool isNonMutatingSetterPWAssignInsideInit(Expr *baseExpr,
68706866
/// the given member.
68716867
static Type adjustSelfTypeForMember(Expr *baseExpr,
68726868
Type baseTy, ValueDecl *member,
6873-
AccessSemantics semantics,
68746869
DeclContext *UseDC) {
6875-
auto baseObjectTy = baseTy->getWithoutSpecifierType();
6870+
assert(!baseTy->is<LValueType>());
6871+
6872+
auto inOutTy = baseTy->getAs<InOutType>();
6873+
if (!inOutTy)
6874+
return baseTy;
6875+
6876+
auto baseObjectTy = inOutTy->getObjectType();
68766877

68776878
if (isa<ConstructorDecl>(member))
68786879
return baseObjectTy;
@@ -6881,7 +6882,7 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
68816882
// If 'self' is an inout type, turn the base type into an lvalue
68826883
// type with the same qualifiers.
68836884
if (func->isMutating())
6884-
return InOutType::get(baseObjectTy);
6885+
return baseTy;
68856886

68866887
// Otherwise, return the rvalue type.
68876888
return baseObjectTy;
@@ -6904,34 +6905,17 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
69046905
!isNonMutatingSetterPWAssignInsideInit(baseExpr, member, UseDC))
69056906
return baseObjectTy;
69066907

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

69296914
Expr *
6930-
ExprRewriter::coerceObjectArgumentToType(Expr *expr,
6931-
Type baseTy, ValueDecl *member,
6932-
AccessSemantics semantics,
6933-
ConstraintLocatorBuilder locator) {
6934-
Type toType = adjustSelfTypeForMember(expr, baseTy, member, semantics, dc);
6915+
ExprRewriter::coerceSelfArgumentToType(Expr *expr,
6916+
Type baseTy, ValueDecl *member,
6917+
ConstraintLocatorBuilder locator) {
6918+
Type toType = adjustSelfTypeForMember(expr, baseTy, member, dc);
69356919

69366920
// If our expression already has the right type, we're done.
69376921
Type fromType = cs.getType(expr);

lib/Sema/CSDiagnostics.cpp

+13-11
Original file line numberDiff line numberDiff line change
@@ -1501,31 +1501,31 @@ bool RValueTreatedAsLValueFailure::diagnoseAsNote() {
15011501
return true;
15021502
}
15031503

1504-
static Decl *findSimpleReferencedDecl(const Expr *E) {
1504+
static VarDecl *findSimpleReferencedVarDecl(const Expr *E) {
15051505
if (auto *LE = dyn_cast<LoadExpr>(E))
15061506
E = LE->getSubExpr();
15071507

15081508
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
1509-
return DRE->getDecl();
1509+
return dyn_cast<VarDecl>(DRE->getDecl());
15101510

15111511
return nullptr;
15121512
}
15131513

1514-
static std::pair<Decl *, Decl *> findReferencedDecl(const Expr *E) {
1514+
static std::pair<VarDecl *, VarDecl *> findReferencedVarDecl(const Expr *E) {
15151515
E = E->getValueProvidingExpr();
15161516

15171517
if (auto *LE = dyn_cast<LoadExpr>(E))
1518-
return findReferencedDecl(LE->getSubExpr());
1518+
return findReferencedVarDecl(LE->getSubExpr());
15191519

15201520
if (auto *AE = dyn_cast<AssignExpr>(E))
1521-
return findReferencedDecl(AE->getDest());
1521+
return findReferencedVarDecl(AE->getDest());
15221522

1523-
if (auto *D = findSimpleReferencedDecl(E))
1523+
if (auto *D = findSimpleReferencedVarDecl(E))
15241524
return std::make_pair(nullptr, D);
15251525

15261526
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
1527-
if (auto *BaseDecl = findSimpleReferencedDecl(MRE->getBase()))
1528-
return std::make_pair(BaseDecl, MRE->getMember().getDecl());
1527+
if (auto *BaseDecl = findSimpleReferencedVarDecl(MRE->getBase()))
1528+
return std::make_pair(BaseDecl, cast<VarDecl>(MRE->getMember().getDecl()));
15291529
}
15301530

15311531
return std::make_pair(nullptr, nullptr);
@@ -1539,10 +1539,12 @@ bool TypeChecker::diagnoseSelfAssignment(const Expr *expr) {
15391539
auto *dstExpr = assignExpr->getDest();
15401540
auto *srcExpr = assignExpr->getSrc();
15411541

1542-
auto dstDecl = findReferencedDecl(dstExpr);
1543-
auto srcDecl = findReferencedDecl(srcExpr);
1542+
auto dstDecl = findReferencedVarDecl(dstExpr);
1543+
auto srcDecl = findReferencedVarDecl(srcExpr);
15441544

1545-
if (dstDecl.second && dstDecl == srcDecl) {
1545+
if (dstDecl.second &&
1546+
dstDecl.second->hasStorage() &&
1547+
dstDecl == srcDecl) {
15461548
auto &DE = dstDecl.second->getASTContext().Diags;
15471549
DE.diagnose(expr->getLoc(), dstDecl.first ? diag::self_assignment_prop
15481550
: diag::self_assignment_var)

test/Sema/diag_self_assign.swift

+81-7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ class SA1 {
2121
}
2222
}
2323

24+
struct SA1a {
25+
var foo: Int = 0
26+
init(fooi: Int) {
27+
var foo = fooi
28+
foo = foo // expected-error {{assigning a variable to itself}}
29+
self.foo = self.foo // expected-error {{assigning a property to itself}}
30+
foo = self.foo // no-error
31+
self.foo = foo // no-error
32+
}
33+
mutating func f(fooi: Int) {
34+
var foo = fooi
35+
foo = foo // expected-error {{assigning a variable to itself}}
36+
self.foo = self.foo // expected-error {{assigning a property to itself}}
37+
foo = self.foo // no-error
38+
self.foo = foo // no-error
39+
}
40+
}
41+
2442
class SA2 {
2543
var foo: Int {
2644
get {
@@ -31,14 +49,37 @@ class SA2 {
3149
init(fooi: Int) {
3250
var foo = fooi
3351
foo = foo // expected-error {{assigning a variable to itself}}
34-
self.foo = self.foo // expected-error {{assigning a property to itself}}
52+
self.foo = self.foo // no-error
3553
foo = self.foo // no-error
3654
self.foo = foo // no-error
3755
}
3856
func f(fooi: Int) {
3957
var foo = fooi
4058
foo = foo // expected-error {{assigning a variable to itself}}
41-
self.foo = self.foo // expected-error {{assigning a property to itself}}
59+
self.foo = self.foo // no-error
60+
foo = self.foo // no-error
61+
self.foo = foo // no-error
62+
}
63+
}
64+
65+
struct SA2a {
66+
var foo: Int {
67+
get {
68+
return 0
69+
}
70+
set {}
71+
}
72+
init(fooi: Int) {
73+
var foo = fooi
74+
foo = foo // expected-error {{assigning a variable to itself}}
75+
self.foo = self.foo // no-error
76+
foo = self.foo // no-error
77+
self.foo = foo // no-error
78+
}
79+
mutating func f(fooi: Int) {
80+
var foo = fooi
81+
foo = foo // expected-error {{assigning a variable to itself}}
82+
self.foo = self.foo // no-error
4283
foo = self.foo // no-error
4384
self.foo = foo // no-error
4485
}
@@ -50,10 +91,24 @@ class SA3 {
5091
return foo // expected-warning {{attempting to access 'foo' within its own getter}} expected-note{{access 'self' explicitly to silence this warning}} {{14-14=self.}}
5192
}
5293
set {
53-
foo = foo // expected-error {{assigning a property to itself}} expected-warning {{attempting to modify 'foo' within its own setter}} expected-note{{access 'self' explicitly to silence this warning}} {{7-7=self.}} expected-warning{{setter argument 'newValue' was never used, but the property was accessed}} expected-note{{did you mean to use 'newValue' instead of accessing the property's current value?}}
54-
self.foo = self.foo // expected-error {{assigning a property to itself}}
55-
foo = self.foo // expected-error {{assigning a property to itself}} expected-warning {{attempting to modify 'foo' within its own setter}} expected-note{{access 'self' explicitly to silence this warning}} {{7-7=self.}}
56-
self.foo = foo // expected-error {{assigning a property to itself}}
94+
foo = foo // expected-warning {{attempting to modify 'foo' within its own setter}} expected-note{{access 'self' explicitly to silence this warning}} {{7-7=self.}} expected-warning{{setter argument 'newValue' was never used, but the property was accessed}} expected-note{{did you mean to use 'newValue' instead of accessing the property's current value?}}
95+
self.foo = self.foo // no-error
96+
foo = self.foo // expected-warning {{attempting to modify 'foo' within its own setter}} expected-note{{access 'self' explicitly to silence this warning}} {{7-7=self.}}
97+
self.foo = foo
98+
}
99+
}
100+
}
101+
102+
struct SA3a {
103+
var foo: Int {
104+
get {
105+
return foo // expected-warning {{attempting to access 'foo' within its own getter}} expected-note{{access 'self' explicitly to silence this warning}} {{14-14=self.}}
106+
}
107+
set {
108+
foo = foo // expected-warning {{attempting to modify 'foo' within its own setter}} expected-note{{access 'self' explicitly to silence this warning}} {{7-7=self.}} expected-warning{{setter argument 'newValue' was never used, but the property was accessed}} expected-note{{did you mean to use 'newValue' instead of accessing the property's current value?}}
109+
self.foo = self.foo // no-error
110+
foo = self.foo // expected-warning {{attempting to modify 'foo' within its own setter}} expected-note{{access 'self' explicitly to silence this warning}} {{7-7=self.}}
111+
self.foo = foo
57112
}
58113
}
59114
}
@@ -69,10 +124,29 @@ class SA4 {
69124
}
70125
}
71126

127+
struct SA4a {
128+
var foo: Int {
129+
get {
130+
return foo // expected-warning {{attempting to access 'foo' within its own getter}} expected-note{{access 'self' explicitly to silence this warning}} {{14-14=self.}}
131+
}
132+
set(value) {
133+
value = value // expected-error {{cannot assign to value: 'value' is a 'let' constant}}
134+
}
135+
}
136+
}
137+
72138
class SA5 {
73139
var foo: Int = 0
74140
}
75-
func SA5_test(a: SA4, b: SA4) {
141+
func SA5_test(a: SA5, b: SA5) {
142+
a.foo = a.foo // expected-error {{assigning a property to itself}}
143+
a.foo = b.foo
144+
}
145+
146+
struct SA5a {
147+
var foo: Int = 0
148+
}
149+
func SA5a_test(a: inout SA5, b: inout SA5) {
76150
a.foo = a.foo // expected-error {{assigning a property to itself}}
77151
a.foo = b.foo
78152
}

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)