Skip to content

Commit ae4de47

Browse files
committed
Sema: Correctly mark backing storage for lazy properties and property wrappers as 'final'
By calling isFinal() first in makeFinal(), we were triggering computation of IsFinalRequest and caching a value of 'false'. With lazy properties, we did direct storage access, and no accessors were synthesized anyway, but add a test for that. With property wrappers this now means the backing storage property is final, as intended (?).
1 parent 729ad65 commit ae4de47

File tree

4 files changed

+36
-26
lines changed

4 files changed

+36
-26
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,6 +1626,11 @@ void swift::completeLazyVarImplementation(VarDecl *VD) {
16261626
VD->getDeclContext());
16271627
Storage->setInterfaceType(StorageInterfaceTy);
16281628
Storage->setUserAccessible(false);
1629+
1630+
// Mark the backing property as 'final'. There's no sensible way to override.
1631+
if (VD->getDeclContext()->getSelfClassDecl())
1632+
makeFinal(Context, Storage);
1633+
16291634
addMemberToContextIfNeeded(Storage, VD->getDeclContext(), VD);
16301635

16311636
// Create the pattern binding decl for the storage decl. This will get
@@ -1642,12 +1647,7 @@ void swift::completeLazyVarImplementation(VarDecl *VD) {
16421647
VD->getGetter()->setBodySynthesizer(&synthesizeLazyGetterBody, Storage);
16431648
VD->getSetter()->setBodySynthesizer(&synthesizeLazySetterBody, Storage);
16441649

1645-
// Mark the vardecl to be final, implicit, and private. In a class, this
1646-
// prevents it from being dynamically dispatched. Note that we do this after
1647-
// the accessors are set up, because we don't want the setter for the lazy
1648-
// property to inherit these properties from the storage.
1649-
if (VD->getDeclContext()->getSelfClassDecl())
1650-
makeFinal(Context, Storage);
1650+
// The storage is implicit and private.
16511651
Storage->setImplicit();
16521652
Storage->overwriteAccess(AccessLevel::Private);
16531653
Storage->overwriteSetterAccess(AccessLevel::Private);
@@ -1796,6 +1796,15 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
17961796
if (isInvalid)
17971797
backingVar->setInvalid();
17981798
backingVar->setOriginalWrappedProperty(var);
1799+
1800+
// Mark the backing property as 'final'. There's no sensible way to override.
1801+
if (dc->getSelfClassDecl())
1802+
makeFinal(ctx, backingVar);
1803+
1804+
// The backing storage is 'private'.
1805+
backingVar->overwriteAccess(AccessLevel::Private);
1806+
backingVar->overwriteSetterAccess(AccessLevel::Private);
1807+
17991808
addMemberToContextIfNeeded(backingVar, dc, var);
18001809

18011810
// Create the pattern binding declaration for the backing property.
@@ -1819,15 +1828,6 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
18191828

18201829
tc.typeCheckPatternBinding(parentPBD, patternNumber);
18211830
}
1822-
// Mark the backing property as 'final'. There's no sensible way to override.
1823-
if (dc->getSelfClassDecl())
1824-
makeFinal(ctx, backingVar);
1825-
1826-
// The backing storage is 'private'.
1827-
backingVar->overwriteAccess(AccessLevel::Private);
1828-
1829-
// Determine setter access.
1830-
backingVar->overwriteSetterAccess(AccessLevel::Private);
18311831

18321832
Expr *originalInitialValue = nullptr;
18331833
if (Expr *init = parentPBD->getInit(patternNumber)) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,10 +1051,8 @@ static void validatePatternBindingEntries(TypeChecker &tc,
10511051
}
10521052

10531053
void swift::makeFinal(ASTContext &ctx, ValueDecl *D) {
1054-
if (D && !D->isFinal()) {
1055-
assert(isa<ClassDecl>(D) || D->isPotentiallyOverridable());
1056-
D->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true));
1057-
}
1054+
assert(isa<ClassDecl>(D) || D->isPotentiallyOverridable());
1055+
D->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true));
10581056
}
10591057

10601058
namespace {

test/SILGen/lazy_properties.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,15 @@ func test21057425() {
3434
struct HasAnonymousParameters {
3535
lazy var x = { $0 }(0)
3636
}
37+
38+
class LazyClass {
39+
lazy var x = 0
40+
}
41+
42+
// CHECK-LABEL: sil hidden [ossa] @$s15lazy_properties9LazyClassC1xSivg : $@convention(method) (@guaranteed LazyClass) -> Int
43+
// CHECK: ref_element_addr %0 : $LazyClass, #LazyClass.$__lazy_storage_$_x
44+
// CHECK: return
45+
46+
// CHECK-LABEL: sil hidden [ossa] @$s15lazy_properties9LazyClassC1xSivs : $@convention(method) (Int, @guaranteed LazyClass) -> ()
47+
// CHECK: ref_element_addr %1 : $LazyClass, #LazyClass.$__lazy_storage_$_x
48+
// CHECK: return

test/SILGen/property_wrappers.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class ClassUsingWrapper {
264264
extension ClassUsingWrapper {
265265
// CHECK-LABEL: sil hidden [ossa] @$s17property_wrappers17ClassUsingWrapperC04testcdE01cyAC_tF : $@convention(method) (@guaranteed ClassUsingWrapper, @guaranteed ClassUsingWrapper) -> () {
266266
func testClassUsingWrapper(c: ClassUsingWrapper) {
267-
// CHECK: class_method [[GETTER:%.*]] : $ClassUsingWrapper, #ClassUsingWrapper.$x!getter.1
267+
// CHECK: ref_element_addr %1 : $ClassUsingWrapper, #ClassUsingWrapper.$x
268268
self.$x.test()
269269
}
270270
}
@@ -298,9 +298,9 @@ class UseWrapperWithDefaultInit {
298298

299299

300300
// CHECK-LABEL: sil_vtable ClassUsingWrapper {
301-
// CHECK: #ClassUsingWrapper.x!getter.1: (ClassUsingWrapper) -> () -> Int : @$s17property_wrappers17ClassUsingWrapperC1xSivg // ClassUsingWrapper.x.getter
302-
// CHECK: #ClassUsingWrapper.x!setter.1: (ClassUsingWrapper) -> (Int) -> () : @$s17property_wrappers17ClassUsingWrapperC1xSivs // ClassUsingWrapper.x.setter
303-
// CHECK: #ClassUsingWrapper.x!modify.1: (ClassUsingWrapper) -> () -> () : @$s17property_wrappers17ClassUsingWrapperC1xSivM // ClassUsingWrapper.x.modify
304-
// CHECK: #ClassUsingWrapper.$x!getter.1: (ClassUsingWrapper) -> () -> WrapperWithInitialValue<Int> : @$s17property_wrappers17ClassUsingWrapperC2$x33_{{.*}}16WithInitialValueVySiGvg // ClassUsingWrapper.$x.getter
305-
// CHECK: #ClassUsingWrapper.$x!setter.1: (ClassUsingWrapper) -> (WrapperWithInitialValue<Int>) -> () : @$s17property_wrappers17ClassUsingWrapperC2$x33_{{.*}}16WithInitialValueVySiGvs // ClassUsingWrapper.$x.setter
306-
// CHECK: #ClassUsingWrapper.$x!modify.1: (ClassUsingWrapper) -> () -> () : @$s17property_wrappers17ClassUsingWrapperC2$x33_{{.*}}16WithInitialValueVySiGvM // ClassUsingWrapper.$x.modify
301+
// CHECK-NEXT: #ClassUsingWrapper.x!getter.1: (ClassUsingWrapper) -> () -> Int : @$s17property_wrappers17ClassUsingWrapperC1xSivg // ClassUsingWrapper.x.getter
302+
// CHECK-NEXT: #ClassUsingWrapper.x!setter.1: (ClassUsingWrapper) -> (Int) -> () : @$s17property_wrappers17ClassUsingWrapperC1xSivs // ClassUsingWrapper.x.setter
303+
// CHECK-NEXT: #ClassUsingWrapper.x!modify.1: (ClassUsingWrapper) -> () -> () : @$s17property_wrappers17ClassUsingWrapperC1xSivM // ClassUsingWrapper.x.modify
304+
// CHECK-NEXT: #ClassUsingWrapper.init!allocator.1: (ClassUsingWrapper.Type) -> () -> ClassUsingWrapper : @$s17property_wrappers17ClassUsingWrapperCACycfC
305+
// CHECK-NEXT: #ClassUsingWrapper.deinit!deallocator.1: @$s17property_wrappers17ClassUsingWrapperCfD
306+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)