Skip to content

Commit 0f2b0f6

Browse files
authored
Merge pull request #30750 from slavapestov/final-static-property-wrapper-fix-5.2
Sema: Property wrapper storage wrappers ($foo) inherit 'final' bit from original property [5.2]
2 parents 231dfd3 + de53a64 commit 0f2b0f6

File tree

4 files changed

+118
-1
lines changed

4 files changed

+118
-1
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,15 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
578578
VD->getOriginalWrappedProperty(PropertyWrapperSynthesizedPropertyKind::Backing))
579579
return true;
580580

581-
if (auto *nominalDecl = VD->getDeclContext()->getSelfClassDecl()) {
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+
589+
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'.
584592
auto *PBD = VD->getParentPatternBinding();
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 init() {}
21+
22+
public var projectedValue: PropertyWrapper {
23+
get {
24+
return self
25+
}
26+
set {
27+
self = newValue
28+
}
29+
}
30+
31+
public var wrappedValue: Bool {
32+
return false
33+
}
34+
}
35+
36+
// CHECK-LABEL: sil [ossa] @$s23property_wrappers_final17useStorageWrapperyyAA7MyClassCF : $@convention(thin) (@guaranteed MyClass) -> () {
37+
public func useStorageWrapper(_ c: MyClass) {
38+
// CHECK: function_ref @$s23property_wrappers_final7MyClassC15$staticPropertyAA0G7WrapperVvgZ
39+
_ = MyClass.$staticProperty
40+
41+
// CHECK: function_ref @$s23property_wrappers_final7MyClassC15$staticPropertyAA0G7WrapperVvsZ
42+
MyClass.$staticProperty = PropertyWrapper()
43+
44+
// CHECK: $s23property_wrappers_final7MyClassC17$instancePropertyAA0G7WrapperVvg
45+
_ = c.$instanceProperty
46+
47+
// CHECK: $s23property_wrappers_final7MyClassC17$instancePropertyAA0G7WrapperVvs
48+
c.$instanceProperty = PropertyWrapper()
49+
50+
// CHECK: return
51+
}
52+
53+
// CHECK-LABEL: sil_vtable [serialized] MyClass {
54+
// CHECK-NEXT: #MyClass.init!allocator.1: (MyClass.Type) -> () -> MyClass : @$s23property_wrappers_final7MyClassCACycfC
55+
// CHECK-NEXT: #MyClass.deinit!deallocator.1: @$s23property_wrappers_final7MyClassCfD
56+
// 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)