Skip to content

Commit 95f8ed8

Browse files
authored
Merge pull request #36711 from hborla/property-wrapper-availability-inference
[Property Wrappers] Fix availability inference of synthesized property wrapper setters
2 parents e1b82d8 + 0a5de7a commit 95f8ed8

File tree

5 files changed

+107
-37
lines changed

5 files changed

+107
-37
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,9 @@ class alignas(1 << DeclAlignInBits) Decl {
789789
return Attrs;
790790
}
791791

792+
/// Returns the innermost enclosing decl with an availability annotation.
793+
const Decl *getInnermostDeclWithAvailability() const;
794+
792795
/// Returns the introduced OS version in the given platform kind specified
793796
/// by @available attribute.
794797
/// This function won't consider the parent context to get the information.

lib/AST/Decl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,19 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) {
351351
llvm_unreachable("bad DescriptiveDeclKind");
352352
}
353353

354+
const Decl *Decl::getInnermostDeclWithAvailability() const {
355+
const Decl *enclosingDecl = this;
356+
// Find the innermost enclosing declaration with an @available annotation.
357+
while (enclosingDecl != nullptr) {
358+
if (enclosingDecl->getAttrs().hasAttribute<AvailableAttr>())
359+
return enclosingDecl;
360+
361+
enclosingDecl = enclosingDecl->getDeclContext()->getAsDecl();
362+
}
363+
364+
return nullptr;
365+
}
366+
354367
Optional<llvm::VersionTuple>
355368
Decl::getIntroducedOSVersion(PlatformKind Kind) const {
356369
for (auto *attr: getAttrs()) {

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,17 +566,15 @@ configureInheritedDesignatedInitAttributes(ClassDecl *classDecl,
566566
// If the superclass has its own availability, make sure the synthesized
567567
// constructor is only as available as its superclass's constructor.
568568
if (superclassCtor->getAttrs().hasAttribute<AvailableAttr>()) {
569-
SmallVector<Decl *, 2> asAvailableAs;
569+
SmallVector<const Decl *, 2> asAvailableAs;
570570

571571
// We don't have to look at enclosing contexts of the superclass constructor,
572572
// because designated initializers must always be defined in the superclass
573573
// body, and we already enforce that a superclass is at least as available as
574574
// a subclass.
575575
asAvailableAs.push_back(superclassCtor);
576-
Decl *parentDecl = classDecl;
577-
while (parentDecl != nullptr) {
576+
if (auto *parentDecl = classDecl->getInnermostDeclWithAvailability()) {
578577
asAvailableAs.push_back(parentDecl);
579-
parentDecl = parentDecl->getDeclContext()->getAsDecl();
580578
}
581579
AvailabilityInference::applyInferredAvailableAttrs(
582580
ctor, asAvailableAs, ctx);

lib/Sema/TypeCheckStorage.cpp

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,45 @@ static AccessorDecl *createGetterPrototype(AbstractStorageDecl *storage,
19261926
return getter;
19271927
}
19281928

1929+
static void addPropertyWrapperAccessorAvailability(VarDecl *var, AccessorKind accessorKind,
1930+
SmallVectorImpl<const Decl *> &asAvailableAs) {
1931+
AccessorDecl *synthesizedFrom = nullptr;
1932+
if (var->hasAttachedPropertyWrapper()) {
1933+
// The property wrapper info may not actually link back to a wrapper
1934+
// 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);
1938+
}
1939+
} else if (auto wrapperSynthesizedKind
1940+
= var->getPropertyWrapperSynthesizedPropertyKind()) {
1941+
switch (*wrapperSynthesizedKind) {
1942+
case PropertyWrapperSynthesizedPropertyKind::Backing:
1943+
break;
1944+
1945+
case PropertyWrapperSynthesizedPropertyKind::Projection: {
1946+
if (auto origVar = var->getOriginalWrappedProperty(wrapperSynthesizedKind)) {
1947+
// The property wrapper info may not actually link back to a wrapper
1948+
// 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);
1952+
}
1953+
}
1954+
break;
1955+
}
1956+
}
1957+
}
1958+
1959+
// Infer availability from the accessor used for synthesis, and intersect it
1960+
// with the availability of the enclosing scope.
1961+
if (synthesizedFrom) {
1962+
asAvailableAs.push_back(synthesizedFrom);
1963+
if (auto *enclosingDecl = var->getInnermostDeclWithAvailability())
1964+
asAvailableAs.push_back(enclosingDecl);
1965+
}
1966+
}
1967+
19291968
static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage,
19301969
ASTContext &ctx,
19311970
AccessorDecl *getter = nullptr) {
@@ -1967,41 +2006,11 @@ static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage,
19672006
assert(storage->requiresOpaqueAccessor(AccessorKind::Set));
19682007

19692008
// Copy availability from the accessor we'll synthesize the setter from.
1970-
SmallVector<Decl *, 2> asAvailableAs;
1971-
2009+
SmallVector<const Decl *, 2> asAvailableAs;
2010+
19722011
// That could be a property wrapper...
19732012
if (auto var = dyn_cast<VarDecl>(storage)) {
1974-
if (var->hasAttachedPropertyWrapper()) {
1975-
// The property wrapper info may not actually link back to a wrapper
1976-
// implementation, if there was a semantic error checking the wrapper.
1977-
auto info = var->getAttachedPropertyWrapperTypeInfo(0);
1978-
if (info.valueVar) {
1979-
if (auto setter = info.valueVar->getOpaqueAccessor(AccessorKind::Set)) {
1980-
asAvailableAs.push_back(setter);
1981-
}
1982-
}
1983-
} else if (auto wrapperSynthesizedKind
1984-
= var->getPropertyWrapperSynthesizedPropertyKind()) {
1985-
switch (*wrapperSynthesizedKind) {
1986-
case PropertyWrapperSynthesizedPropertyKind::Backing:
1987-
break;
1988-
1989-
case PropertyWrapperSynthesizedPropertyKind::Projection: {
1990-
if (auto origVar = var->getOriginalWrappedProperty(wrapperSynthesizedKind)) {
1991-
// The property wrapper info may not actually link back to a wrapper
1992-
// implementation, if there was a semantic error checking the wrapper.
1993-
auto info = origVar->getAttachedPropertyWrapperTypeInfo(0);
1994-
if (info.projectedValueVar) {
1995-
if (auto setter
1996-
= info.projectedValueVar->getOpaqueAccessor(AccessorKind::Set)){
1997-
asAvailableAs.push_back(setter);
1998-
}
1999-
}
2000-
}
2001-
break;
2002-
}
2003-
}
2004-
}
2013+
addPropertyWrapperAccessorAvailability(var, AccessorKind::Set, asAvailableAs);
20052014
}
20062015

20072016

@@ -2095,6 +2104,10 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage,
20952104
}
20962105
}
20972106

2107+
if (auto var = dyn_cast<VarDecl>(storage)) {
2108+
addPropertyWrapperAccessorAvailability(var, kind, asAvailableAs);
2109+
}
2110+
20982111
AvailabilityInference::applyInferredAvailableAttrs(accessor,
20992112
asAvailableAs, ctx);
21002113

test/Sema/generalized_accessors_availability.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,46 @@ func butt(x: inout Butt) { // expected-note*{{}}
6767
x.$wrapped_modify_conditionally_available = 0
6868
}
6969
}
70+
71+
@available(macOS 11.0, *)
72+
struct LessAvailable {
73+
@SetterConditionallyAvailable
74+
var wrapped_setter_more_available: Int
75+
76+
@ModifyConditionallyAvailable
77+
var wrapped_modify_more_available: Int
78+
79+
var nested: Nested
80+
81+
struct Nested {
82+
@SetterConditionallyAvailable
83+
var wrapped_setter_more_available: Int
84+
85+
@ModifyConditionallyAvailable
86+
var wrapped_modify_more_available: Int
87+
}
88+
}
89+
90+
func testInferredAvailability(x: inout LessAvailable) { // expected-error {{'LessAvailable' is only available in macOS 11.0 or newer}} expected-note*{{}}
91+
x.wrapped_setter_more_available = 0 // expected-error {{setter for 'wrapped_setter_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
92+
x.wrapped_modify_more_available = 0 // expected-error {{setter for 'wrapped_modify_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
93+
x.$wrapped_setter_more_available = 0 // expected-error {{setter for '$wrapped_setter_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
94+
x.$wrapped_modify_more_available = 0 // expected-error {{setter for '$wrapped_modify_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
95+
96+
x.nested.wrapped_setter_more_available = 0 // expected-error {{setter for 'wrapped_setter_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
97+
x.nested.wrapped_modify_more_available = 0 // expected-error {{setter for 'wrapped_modify_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
98+
x.nested.$wrapped_setter_more_available = 0 // expected-error {{setter for '$wrapped_setter_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
99+
x.nested.$wrapped_modify_more_available = 0 // expected-error {{setter for '$wrapped_modify_more_available' is only available in macOS 11.0 or newer}} expected-note{{}}
100+
101+
if #available(macOS 11.0, *) {
102+
x.wrapped_setter_more_available = 0
103+
x.wrapped_modify_more_available = 0
104+
x.$wrapped_setter_more_available = 0
105+
x.$wrapped_modify_more_available = 0
106+
107+
x.nested.wrapped_setter_more_available = 0
108+
x.nested.wrapped_modify_more_available = 0
109+
x.nested.$wrapped_setter_more_available = 0
110+
x.nested.$wrapped_modify_more_available = 0
111+
}
112+
}

0 commit comments

Comments
 (0)