Skip to content

Commit b774acd

Browse files
committed
[Property Wrappers] If a property wrapper accessor is synthesized using the
enclosing-self subscript, infer availability from accessors on the subscript declaration.
1 parent 57aa7e4 commit b774acd

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

lib/Sema/TypeCheckStorage.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,11 +1930,17 @@ static void addPropertyWrapperAccessorAvailability(VarDecl *var, AccessorKind ac
19301930
SmallVectorImpl<const Decl *> &asAvailableAs) {
19311931
AccessorDecl *synthesizedFrom = nullptr;
19321932
if (var->hasAttachedPropertyWrapper()) {
1933+
AbstractStorageDecl *wrappedValueImpl;
1934+
if (auto access = getEnclosingSelfPropertyWrapperAccess(var, /*forProjected=*/false)) {
1935+
wrappedValueImpl = access->subscript;
1936+
} else {
1937+
wrappedValueImpl = var->getAttachedPropertyWrapperTypeInfo(0).valueVar;
1938+
}
1939+
19331940
// The property wrapper info may not actually link back to a wrapper
19341941
// implementation, if there was a semantic error checking the wrapper.
1935-
auto info = var->getAttachedPropertyWrapperTypeInfo(0);
1936-
if (info.valueVar) {
1937-
synthesizedFrom = info.valueVar->getOpaqueAccessor(accessorKind);
1942+
if (wrappedValueImpl) {
1943+
synthesizedFrom = wrappedValueImpl->getOpaqueAccessor(accessorKind);
19381944
}
19391945
} else if (auto wrapperSynthesizedKind
19401946
= var->getPropertyWrapperSynthesizedPropertyKind()) {
@@ -1944,11 +1950,17 @@ static void addPropertyWrapperAccessorAvailability(VarDecl *var, AccessorKind ac
19441950

19451951
case PropertyWrapperSynthesizedPropertyKind::Projection: {
19461952
if (auto origVar = var->getOriginalWrappedProperty(wrapperSynthesizedKind)) {
1953+
AbstractStorageDecl *projectedValueImpl;
1954+
if (auto access = getEnclosingSelfPropertyWrapperAccess(origVar, /*forProjected=*/true)) {
1955+
projectedValueImpl = access->subscript;
1956+
} else {
1957+
projectedValueImpl = origVar->getAttachedPropertyWrapperTypeInfo(0).projectedValueVar;
1958+
}
1959+
19471960
// The property wrapper info may not actually link back to a wrapper
19481961
// implementation, if there was a semantic error checking the wrapper.
1949-
auto info = origVar->getAttachedPropertyWrapperTypeInfo(0);
1950-
if (info.projectedValueVar) {
1951-
synthesizedFrom = info.projectedValueVar->getOpaqueAccessor(accessorKind);
1962+
if (projectedValueImpl) {
1963+
synthesizedFrom = projectedValueImpl->getOpaqueAccessor(accessorKind);
19521964
}
19531965
}
19541966
break;

test/Sema/generalized_accessors_availability.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,42 @@ func testInferredAvailability(x: inout LessAvailable) { // expected-error {{'Les
110110
x.nested.$wrapped_modify_more_available = 0
111111
}
112112
}
113+
114+
@propertyWrapper
115+
struct Observable<Value> {
116+
private var stored: Value
117+
118+
init(wrappedValue: Value) { self.stored = wrappedValue }
119+
120+
@available(*, unavailable)
121+
var wrappedValue: Value {
122+
get { fatalError() }
123+
set { fatalError() }
124+
}
125+
126+
static subscript<EnclosingSelf>(
127+
_enclosingInstance observed: EnclosingSelf,
128+
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
129+
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
130+
) -> Value {
131+
get { observed[keyPath: storageKeyPath].stored }
132+
set { observed[keyPath: storageKeyPath].stored = newValue }
133+
}
134+
}
135+
136+
protocol P {}
137+
138+
class Base<T: P> {
139+
@Observable var item: T?
140+
}
141+
142+
struct Item: P {}
143+
144+
class Subclass: Base<Item> {
145+
// Make sure this override isn't incorrectly diagnosed as
146+
// unavailable. Wrapper availability inference should infer
147+
// availability from the static subscript in this case.
148+
override var item: Item? {
149+
didSet {}
150+
}
151+
}

0 commit comments

Comments
 (0)