Skip to content

Commit 61bf796

Browse files
authored
Merge pull request swiftlang#30745 from slavapestov/final-static-property-wrapper-fix
Sema: Property wrapper storage wrappers ($foo) inherit 'final' bit from original property
2 parents 630d0f6 + 52c11c7 commit 61bf796

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
578578
VD->getOriginalWrappedProperty(PropertyWrapperSynthesizedPropertyKind::Backing))
579579
return true;
580580

581+
// Property wrapper storage wrappers are final if the original property
582+
// is final.
583+
if (auto *original = VD->getOriginalWrappedProperty(
584+
PropertyWrapperSynthesizedPropertyKind::StorageWrapper)) {
585+
if (original->isFinal())
586+
return true;
587+
}
588+
581589
if (VD->getDeclContext()->getSelfClassDecl()) {
582590
// If this variable is a class member, mark it final if the
583591
// class is final, or if it was declared with 'let'.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
3+
4+
// Test that the storage wrapper for a final property is itself final, and that
5+
// its accessors do not appear in the vtable.
6+
7+
public class MyClass {
8+
public init() { }
9+
10+
@PropertyWrapper()
11+
public static var staticProperty: Bool
12+
13+
@PropertyWrapper()
14+
public final var instanceProperty: Bool
15+
16+
}
17+
18+
@propertyWrapper
19+
public struct PropertyWrapper {
20+
public var projectedValue: PropertyWrapper {
21+
get {
22+
return self
23+
}
24+
set {
25+
self = newValue
26+
}
27+
}
28+
29+
public var wrappedValue: Bool {
30+
return false
31+
}
32+
}
33+
34+
// CHECK-LABEL: sil [ossa] @$s23property_wrappers_final17useStorageWrapperyyAA7MyClassCF : $@convention(thin) (@guaranteed MyClass) -> () {
35+
public func useStorageWrapper(_ c: MyClass) {
36+
// CHECK: function_ref @$s23property_wrappers_final7MyClassC15$staticPropertyAA0G7WrapperVvgZ
37+
_ = MyClass.$staticProperty
38+
39+
// CHECK: function_ref @$s23property_wrappers_final7MyClassC15$staticPropertyAA0G7WrapperVvsZ
40+
MyClass.$staticProperty = PropertyWrapper()
41+
42+
// CHECK: $s23property_wrappers_final7MyClassC17$instancePropertyAA0G7WrapperVvg
43+
_ = c.$instanceProperty
44+
45+
// CHECK: $s23property_wrappers_final7MyClassC17$instancePropertyAA0G7WrapperVvs
46+
c.$instanceProperty = PropertyWrapper()
47+
48+
// CHECK: return
49+
}
50+
51+
// CHECK-LABEL: sil_vtable [serialized] MyClass {
52+
// CHECK-NEXT: #MyClass.init!allocator: (MyClass.Type) -> () -> MyClass : @$s23property_wrappers_final7MyClassCACycfC
53+
// CHECK-NEXT: #MyClass.deinit!deallocator: @$s23property_wrappers_final7MyClassCfD
54+
// CHECK-NEXT: }

test/multifile/Inputs/sr12429.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
public class MyClass {
2+
public init() { }
3+
4+
@PropertyWrapper(key: "key", defaultValue: false)
5+
public static var wrappedProperty: Bool
6+
7+
public var otherProperty: String? {
8+
didSet {
9+
fatalError("Set this other property with value: \(String(describing: otherProperty)), even though we called `myClass.property = `")
10+
}
11+
}
12+
13+
public var property: String? {
14+
didSet {
15+
print("Set expected property: \(String(describing: property))")
16+
}
17+
}
18+
}
19+
20+
@propertyWrapper
21+
public struct PropertyWrapper<Value> {
22+
public let key: String
23+
public let defaultValue: Value
24+
25+
public var projectedValue: PropertyWrapper<Value> {
26+
get {
27+
return self
28+
}
29+
// Having this setter is what causes the mis-compilation
30+
set {
31+
self = newValue
32+
}
33+
}
34+
35+
public var wrappedValue: Value {
36+
return defaultValue
37+
}
38+
39+
public init(key: String, defaultValue: Value) {
40+
self.key = key
41+
self.defaultValue = defaultValue
42+
}
43+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: cp %s %t/main.swift
3+
// RUN: %target-build-swift -o %t/main %t/main.swift %S/Inputs/sr12429.swift
4+
// RUN: %target-codesign %t/main
5+
// RUN: %target-run %t/main
6+
7+
// REQUIRES: executable_test
8+
9+
let object = MyClass()
10+
object.property = "value"

0 commit comments

Comments
 (0)