Skip to content

Commit 8f43d88

Browse files
committed
Sema: Disallow usage of settable Self-returning storage requirements on existential base
1 parent 2fb3c7c commit 8f43d88

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

lib/AST/Decl.cpp

+16-12
Original file line numberDiff line numberDiff line change
@@ -4946,21 +4946,19 @@ ProtocolDecl::findProtocolSelfReferences(const ValueDecl *value,
49464946
return result;
49474947
}
49484948

4949-
return ::findProtocolSelfReferences(this, type,
4950-
skipAssocTypes);
4951-
} else if (auto subscript = dyn_cast<SubscriptDecl>(value)) {
4952-
// Check the requirements of a generic subscript.
4953-
if (subscript->isGeneric()) {
4954-
if (auto result =
4955-
::findProtocolSelfReferences(this,
4956-
subscript->getGenericSignature()))
4957-
return result;
4958-
}
4959-
49604949
return ::findProtocolSelfReferences(this, type,
49614950
skipAssocTypes);
49624951
} else {
4963-
assert(isa<VarDecl>(value));
4952+
assert(isa<AbstractStorageDecl>(value));
4953+
4954+
if (auto *const subscript = dyn_cast<SubscriptDecl>(value)) {
4955+
// Check the requirements of a generic subscript.
4956+
if (subscript->isGeneric()) {
4957+
if (auto result = ::findProtocolSelfReferences(
4958+
this, subscript->getGenericSignature()))
4959+
return result;
4960+
}
4961+
}
49644962

49654963
return ::findProtocolSelfReferences(this, type,
49664964
skipAssocTypes);
@@ -4978,6 +4976,12 @@ bool ProtocolDecl::isAvailableInExistential(const ValueDecl *decl) const {
49784976
if (selfKind.parameter || selfKind.other)
49794977
return false;
49804978

4979+
// FIXME: Appropriately diagnose assignments instead.
4980+
if (auto *const storageDecl = dyn_cast<AbstractStorageDecl>(decl)) {
4981+
if (selfKind.result && storageDecl->supportsMutation())
4982+
return false;
4983+
}
4984+
49814985
return true;
49824986
}
49834987

test/decl/protocol/req/dynamic_self.swift

+36
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,39 @@ enum EError : P { // expected-error{{type 'EError' does not conform to protocol
8686
subscript() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
8787
func f() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
8888
}
89+
90+
91+
// Settable storage declaration requirements with a 'Self' result type may not
92+
// be used with an existential base.
93+
protocol P2 {
94+
subscript() -> Self { get set }
95+
}
96+
protocol P3 {
97+
var prop: Self { get set }
98+
}
99+
protocol P4 {
100+
subscript<T: Sequence>() -> T where T.Element == Self { get set }
101+
}
102+
func takesP2P3P4(p2: P2, p3: P3, p4: P4) { }
103+
// expected-error@-1{{protocol 'P2' can only be used as a generic constraint because it has Self or associated type requirements}}
104+
// expected-error@-2{{protocol 'P3' can only be used as a generic constraint because it has Self or associated type requirements}}
105+
106+
protocol P5 {
107+
}
108+
extension P5 {
109+
var prop: Self {
110+
get { self }
111+
set { }
112+
}
113+
114+
subscript() -> Self {
115+
get { self }
116+
set { }
117+
}
118+
}
119+
func takesP5(p5: P5) {
120+
_ = p5[]
121+
// expected-error@-1{{member 'subscript' cannot be used on value of protocol type 'P5'; use a generic constraint instead}}
122+
_ = p5.prop
123+
// expected-error@-1{{member 'prop' cannot be used on value of protocol type 'P5'; use a generic constraint instead}}
124+
}

0 commit comments

Comments
 (0)