Skip to content

Sema: Disallow usage of settable Self-returning storage requirements … #34214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4946,21 +4946,19 @@ ProtocolDecl::findProtocolSelfReferences(const ValueDecl *value,
return result;
}

return ::findProtocolSelfReferences(this, type,
skipAssocTypes);
} else if (auto subscript = dyn_cast<SubscriptDecl>(value)) {
// Check the requirements of a generic subscript.
if (subscript->isGeneric()) {
if (auto result =
::findProtocolSelfReferences(this,
subscript->getGenericSignature()))
return result;
}

return ::findProtocolSelfReferences(this, type,
skipAssocTypes);
} else {
assert(isa<VarDecl>(value));
assert(isa<AbstractStorageDecl>(value));

if (auto *const subscript = dyn_cast<SubscriptDecl>(value)) {
// Check the requirements of a generic subscript.
if (subscript->isGeneric()) {
if (auto result = ::findProtocolSelfReferences(
this, subscript->getGenericSignature()))
return result;
}
}

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

// FIXME: Appropriately diagnose assignments instead.
if (auto *const storageDecl = dyn_cast<AbstractStorageDecl>(decl)) {
if (selfKind.result && storageDecl->supportsMutation())
return false;
}

return true;
}

Expand Down
36 changes: 36 additions & 0 deletions test/decl/protocol/req/dynamic_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,39 @@ enum EError : P { // expected-error{{type 'EError' does not conform to protocol
subscript() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
func f() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
}


// Settable storage declaration requirements with a 'Self' result type may not
// be used with an existential base.
protocol P2 {
subscript() -> Self { get set }
}
protocol P3 {
var prop: Self { get set }
}
protocol P4 {
subscript<T: Sequence>() -> T where T.Element == Self { get set }
}
func takesP2P3P4(p2: P2, p3: P3, p4: P4) { }
// expected-error@-1{{protocol 'P2' can only be used as a generic constraint because it has Self or associated type requirements}}
// expected-error@-2{{protocol 'P3' can only be used as a generic constraint because it has Self or associated type requirements}}

protocol P5 {
}
extension P5 {
var prop: Self {
get { self }
set { }
}

subscript() -> Self {
get { self }
set { }
}
}
func takesP5(p5: P5) {
_ = p5[]
// expected-error@-1{{member 'subscript' cannot be used on value of protocol type 'P5'; use a generic constraint instead}}
_ = p5.prop
// expected-error@-1{{member 'prop' cannot be used on value of protocol type 'P5'; use a generic constraint instead}}
}