Skip to content

Commit 2e1b6e7

Browse files
committed
Sema: KeyPath literals should be read-only when referring to unavailable setters.
Part of rdar://problem/65152582, where key paths were generating references to setters in contexts where they weren't available.
1 parent e74e914 commit 2e1b6e7

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6268,7 +6268,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
62686268
// If this is an attempt to access read-only member via
62696269
// writable key path, let's fail this choice early.
62706270
auto &ctx = getASTContext();
6271-
if (isReadOnlyKeyPathComponent(storage) &&
6271+
if (isReadOnlyKeyPathComponent(storage, SourceLoc()) &&
62726272
(keyPath == ctx.getWritableKeyPathDecl() ||
62736273
keyPath == ctx.getReferenceWritableKeyPathDecl())) {
62746274
result.addUnviable(
@@ -8020,7 +8020,7 @@ ConstraintSystem::simplifyKeyPathConstraint(
80208020
if (!storage)
80218021
return SolutionKind::Error;
80228022

8023-
if (isReadOnlyKeyPathComponent(storage)) {
8023+
if (isReadOnlyKeyPathComponent(storage, component.getLoc())) {
80248024
capability = ReadOnly;
80258025
continue;
80268026
}

lib/Sema/ConstraintSystem.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4617,7 +4617,8 @@ class ConstraintSystem {
46174617
bool restoreOnFail,
46184618
llvm::function_ref<bool(Constraint *)> pred);
46194619

4620-
bool isReadOnlyKeyPathComponent(const AbstractStorageDecl *storage) {
4620+
bool isReadOnlyKeyPathComponent(const AbstractStorageDecl *storage,
4621+
SourceLoc referenceLoc) {
46214622
// See whether key paths can store to this component. (Key paths don't
46224623
// get any special power from being formed in certain contexts, such
46234624
// as the ability to assign to `let`s in initialization contexts, so
@@ -4638,6 +4639,17 @@ class ConstraintSystem {
46384639
// a reference-writable component shows up later.
46394640
return true;
46404641
}
4642+
4643+
// If the setter is unavailable, then the keypath ought to be read-only
4644+
// in this context.
4645+
if (auto setter = storage->getOpaqueAccessor(AccessorKind::Set)) {
4646+
auto maybeUnavail = TypeChecker::checkDeclarationAvailability(setter,
4647+
referenceLoc,
4648+
DC);
4649+
if (maybeUnavail.hasValue()) {
4650+
return true;
4651+
}
4652+
}
46414653

46424654
return false;
46434655
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.9 -typecheck -verify %s
2+
// REQUIRES: OS=macosx
3+
4+
struct Butt {
5+
var setter_conditionally_available: Int {
6+
get { fatalError() }
7+
8+
@available(macOS 10.10, *)
9+
set { fatalError() }
10+
}
11+
}
12+
13+
func assertExactType<T>(of _: inout T, is _: T.Type) {}
14+
15+
@available(macOS 10.9, *)
16+
public func unavailableSetterContext() {
17+
var kp = \Butt.setter_conditionally_available
18+
assertExactType(of: &kp, is: KeyPath<Butt, Int>.self)
19+
}
20+
@available(macOS 10.10, *)
21+
public func availableSetterContext() {
22+
var kp = \Butt.setter_conditionally_available
23+
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
24+
}
25+
@available(macOS 10.9, *)
26+
public func conditionalAvailableSetterContext() {
27+
if #available(macOS 10.10, *) {
28+
var kp = \Butt.setter_conditionally_available
29+
assertExactType(of: &kp, is: WritableKeyPath<Butt, Int>.self)
30+
} else {
31+
var kp = \Butt.setter_conditionally_available
32+
assertExactType(of: &kp, is: KeyPath<Butt, Int>.self)
33+
}
34+
}
35+

0 commit comments

Comments
 (0)