Skip to content

Commit 99380bf

Browse files
committed
Sema: Sometimes allow universally unavailable declarations to be referenced.
In implicit contexts that are universally unavailable, allow writable key paths to be formed to properties with setters that are also marked as universally unavailable. This fixes a regression from the previous commit where the code synthesized for `@Observable` properties in universally unavailable classes was rejected by the availability checker.
1 parent 4076fa6 commit 99380bf

File tree

6 files changed

+61
-7
lines changed

6 files changed

+61
-7
lines changed

include/swift/AST/AvailabilityConstraint.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ enum class AvailabilityConstraintFlag : uint8_t {
174174
/// Include constraints for all domains, regardless of whether they are active
175175
/// or relevant to type checking.
176176
IncludeAllDomains = 1 << 1,
177+
178+
/// By default, non-type declarations that are universally unavailable are
179+
/// always diagnosed, regardless of whether the context of the reference
180+
/// is also universally unavailable. If this flag is set, though, those
181+
/// references are allowed.
182+
AllowUniversallyUnavailableInCompatibleContexts = 1 << 2,
177183
};
178184
using AvailabilityConstraintFlags = OptionSet<AvailabilityConstraintFlag>;
179185

lib/AST/AvailabilityConstraint.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,16 @@ DeclAvailabilityConstraints::getPrimaryConstraint() const {
118118
}
119119

120120
static bool canIgnoreConstraintInUnavailableContexts(
121-
const Decl *decl, const AvailabilityConstraint &constraint) {
121+
const Decl *decl, const AvailabilityConstraint &constraint,
122+
const AvailabilityConstraintFlags flags) {
122123
auto domain = constraint.getDomain();
123124

124125
switch (constraint.getReason()) {
125126
case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
127+
if (flags.contains(AvailabilityConstraintFlag::
128+
AllowUniversallyUnavailableInCompatibleContexts))
129+
return true;
130+
126131
// Always reject uses of universally unavailable declarations, regardless
127132
// of context, since there are no possible compilation configurations in
128133
// which they are available. However, make an exception for types and
@@ -162,11 +167,12 @@ static bool canIgnoreConstraintInUnavailableContexts(
162167
static bool
163168
shouldIgnoreConstraintInContext(const Decl *decl,
164169
const AvailabilityConstraint &constraint,
165-
const AvailabilityContext &context) {
170+
const AvailabilityContext &context,
171+
const AvailabilityConstraintFlags flags) {
166172
if (!context.isUnavailable())
167173
return false;
168174

169-
if (!canIgnoreConstraintInUnavailableContexts(decl, constraint))
175+
if (!canIgnoreConstraintInUnavailableContexts(decl, constraint, flags))
170176
return false;
171177

172178
return context.containsUnavailableDomain(constraint.getDomain());
@@ -256,7 +262,7 @@ static void getAvailabilityConstraintsForDecl(
256262
// declaration is unconditionally unavailable in a domain for which
257263
// the context is already unavailable.
258264
llvm::erase_if(constraints, [&](const AvailabilityConstraint &constraint) {
259-
return shouldIgnoreConstraintInContext(decl, constraint, context);
265+
return shouldIgnoreConstraintInContext(decl, constraint, context, flags);
260266
});
261267
}
262268

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1771,8 +1771,17 @@ std::optional<AvailabilityConstraint>
17711771
swift::getUnsatisfiedAvailabilityConstraint(const Decl *decl,
17721772
const DeclContext *referenceDC,
17731773
SourceLoc referenceLoc) {
1774+
AvailabilityConstraintFlags flags;
1775+
1776+
// In implicit code, allow references to universally unavailable declarations
1777+
// as long as the context is also universally unavailable.
1778+
if (referenceLoc.isInvalid())
1779+
flags |= AvailabilityConstraintFlag::
1780+
AllowUniversallyUnavailableInCompatibleContexts;
1781+
17741782
return getAvailabilityConstraintsForDecl(
1775-
decl, AvailabilityContext::forLocation(referenceLoc, referenceDC))
1783+
decl, AvailabilityContext::forLocation(referenceLoc, referenceDC),
1784+
flags)
17761785
.getPrimaryConstraint();
17771786
}
17781787

lib/Sema/TypeCheckStorage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ getPropertyWrapperLValueness(VarDecl *var) {
10631063
/// - Wrapped: \c self._member.wrappedValue
10641064
/// - Composition: \c self._member.wrappedValue.wrappedValue….wrappedValue
10651065
/// - Projected: \c self._member.projectedValue
1066-
/// - Enclosed instance: \c Wrapper[_enclosedInstance: self, …]
1066+
/// - Enclosed instance: \c Wrapper[_enclosingInstance: self, …]
10671067
static Expr *buildStorageReference(AccessorDecl *accessor,
10681068
AbstractStorageDecl *storage,
10691069
TargetImpl target,

test/Availability/property_wrapper_availability.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,36 @@ func unavailableOnMacOSFunc(
186186
@WrappedValueUnavailableOnMacOS var unavailableWrappedValueLocal = S()
187187
@WrappedValueAvailable51 var wrappedValueAavailable51 = S()
188188
}
189+
190+
@propertyWrapper
191+
struct Observable<Value> {
192+
private var stored: Value
193+
194+
init(wrappedValue: Value) {
195+
self.stored = wrappedValue
196+
}
197+
198+
var wrappedValue: Value {
199+
get { fatalError() }
200+
set { fatalError() }
201+
}
202+
203+
static subscript<EnclosingSelf>(
204+
_enclosingInstance observed: EnclosingSelf,
205+
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
206+
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
207+
) -> Value {
208+
get { fatalError() }
209+
set { fatalError() }
210+
}
211+
}
212+
213+
@available(macOS, unavailable)
214+
class UnavailableOnMacOSObserved {
215+
@Observable var observedProperty = 17
216+
}
217+
218+
@available(*, unavailable)
219+
class UniversallyUnavailableObserved {
220+
@Observable var observedProperty = 17
221+
}

test/expr/unary/keypath/keypath-availability.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,5 @@ public func universallyUnavailable() {
124124
var kp3 = \Butt.setter_universally_unavailable
125125
assertExactType(of: &kp3, is: KeyPath<Butt, Int>.self)
126126
_ = lens.setter_universally_unavailable
127-
lens.setter_universally_unavailable = Lens(1) // expected-error {{cannot assign to property: 'lens' is immutable}}
127+
lens.setter_universally_unavailable = Lens(1)
128128
}

0 commit comments

Comments
 (0)