Skip to content

Commit 85b549a

Browse files
committed
Sema: Synthesized setters get the availability of the decl they're synthesized from.
If a modify/mutableAddress coroutine is defined with availability, or a property wrapper adds a setter with availability, then the implicit synthesized setter should be as available as those declarations it's synthesized from. rdar://problem/65152582
1 parent 2e1b6e7 commit 85b549a

File tree

2 files changed

+138
-1
lines changed

2 files changed

+138
-1
lines changed

lib/Sema/TypeCheckStorage.cpp

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,7 @@ synthesizeSetterBody(AccessorDecl *setter, ASTContext &ctx) {
16591659
case WriteImplKind::Modify:
16601660
return synthesizeModifyCoroutineSetterBody(setter, ctx);
16611661
}
1662-
llvm_unreachable("bad ReadImplKind");
1662+
llvm_unreachable("bad WriteImplKind");
16631663
}
16641664

16651665
static std::pair<BraceStmt *, bool>
@@ -1940,7 +1940,75 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage,
19401940

19411941
// All mutable storage requires a setter.
19421942
assert(storage->requiresOpaqueAccessor(AccessorKind::Set));
1943+
1944+
// Copy availability from the accessor we'll synthesize the setter from.
1945+
SmallVector<Decl *, 2> asAvailableAs;
1946+
1947+
// That could be a property wrapper...
1948+
if (auto var = dyn_cast<VarDecl>(storage)) {
1949+
if (var->hasAttachedPropertyWrapper()) {
1950+
// The property wrapper info may not actually link back to a wrapper
1951+
// implementation, if there was a semantic error checking the wrapper.
1952+
auto info = var->getAttachedPropertyWrapperTypeInfo(0);
1953+
if (info.valueVar) {
1954+
if (auto setter = info.valueVar->getOpaqueAccessor(AccessorKind::Set)) {
1955+
asAvailableAs.push_back(setter);
1956+
}
1957+
}
1958+
} else if (auto wrapperSynthesizedKind
1959+
= var->getPropertyWrapperSynthesizedPropertyKind()) {
1960+
switch (*wrapperSynthesizedKind) {
1961+
case PropertyWrapperSynthesizedPropertyKind::Backing:
1962+
break;
1963+
1964+
case PropertyWrapperSynthesizedPropertyKind::StorageWrapper: {
1965+
if (auto origVar = var->getOriginalWrappedProperty(wrapperSynthesizedKind)) {
1966+
// The property wrapper info may not actually link back to a wrapper
1967+
// implementation, if there was a semantic error checking the wrapper.
1968+
auto info = origVar->getAttachedPropertyWrapperTypeInfo(0);
1969+
if (info.projectedValueVar) {
1970+
if (auto setter
1971+
= info.projectedValueVar->getOpaqueAccessor(AccessorKind::Set)){
1972+
asAvailableAs.push_back(setter);
1973+
}
1974+
}
1975+
}
1976+
break;
1977+
}
1978+
}
1979+
}
1980+
}
19431981

1982+
1983+
// ...or another accessor.
1984+
switch (storage->getWriteImpl()) {
1985+
case WriteImplKind::Immutable:
1986+
llvm_unreachable("synthesizing setter from immutable storage");
1987+
case WriteImplKind::Stored:
1988+
case WriteImplKind::StoredWithObservers:
1989+
case WriteImplKind::InheritedWithObservers:
1990+
case WriteImplKind::Set:
1991+
// Setter's availability shouldn't be externally influenced in these
1992+
// cases.
1993+
break;
1994+
1995+
case WriteImplKind::MutableAddress:
1996+
if (auto addr = storage->getOpaqueAccessor(AccessorKind::MutableAddress)) {
1997+
asAvailableAs.push_back(addr);
1998+
}
1999+
break;
2000+
case WriteImplKind::Modify:
2001+
if (auto mod = storage->getOpaqueAccessor(AccessorKind::Modify)) {
2002+
asAvailableAs.push_back(mod);
2003+
}
2004+
break;
2005+
}
2006+
2007+
if (!asAvailableAs.empty()) {
2008+
AvailabilityInference::applyInferredAvailableAttrs(
2009+
setter, asAvailableAs, ctx);
2010+
}
2011+
19442012
finishImplicitAccessor(setter, ctx);
19452013

19462014
return setter;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.9 -typecheck -verify %s
3+
4+
// REQUIRES: OS=macosx
5+
6+
@propertyWrapper
7+
struct SetterConditionallyAvailable<T> {
8+
var wrappedValue: T {
9+
get { fatalError() }
10+
11+
@available(macOS 10.10, *)
12+
set { fatalError() }
13+
}
14+
15+
var projectedValue: T {
16+
get { fatalError() }
17+
18+
@available(macOS 10.10, *)
19+
set { fatalError() }
20+
}
21+
}
22+
23+
@propertyWrapper
24+
struct ModifyConditionallyAvailable<T> {
25+
var wrappedValue: T {
26+
get { fatalError() }
27+
28+
@available(macOS 10.10, *)
29+
_modify { fatalError() }
30+
}
31+
32+
var projectedValue: T {
33+
get { fatalError() }
34+
35+
@available(macOS 10.10, *)
36+
_modify { fatalError() }
37+
}
38+
}
39+
40+
struct Butt {
41+
var modify_conditionally_available: Int {
42+
get { fatalError() }
43+
44+
@available(macOS 10.10, *)
45+
_modify { fatalError() }
46+
}
47+
48+
@SetterConditionallyAvailable
49+
var wrapped_setter_conditionally_available: Int
50+
51+
@ModifyConditionallyAvailable
52+
var wrapped_modify_conditionally_available: Int
53+
}
54+
55+
func butt(x: inout Butt) { // expected-note*{{}}
56+
x.modify_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
57+
x.wrapped_setter_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
58+
x.wrapped_modify_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
59+
x.$wrapped_setter_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
60+
x.$wrapped_modify_conditionally_available = 0 // expected-error{{only available in macOS 10.10 or newer}} expected-note{{}}
61+
62+
if #available(macOS 10.10, *) {
63+
x.modify_conditionally_available = 0
64+
x.wrapped_setter_conditionally_available = 0
65+
x.wrapped_modify_conditionally_available = 0
66+
x.$wrapped_setter_conditionally_available = 0
67+
x.$wrapped_modify_conditionally_available = 0
68+
}
69+
}

0 commit comments

Comments
 (0)