Skip to content

Commit a360b45

Browse files
committed
Sema: Fix some issues with overrides of materializeForSet
When overriding storage with a forced static dispatch materializeForSet, the override's materializeForSet should not override the base materializeForSet. This is the case where a dynamic property witnesses a protocol requirement, and Sema synthesizes a materializeForSet for it. In this case, the synthesized materializeForSet dynamically dispatches to the dynamic property's getter and setter, and the protocol witness thunk directly calls the synthesized materializeForSet. The subclass only needs to override the getter and setter in this case, since the base class's materializeForSet will already do the right thing. In fact, marking it as an override exposes a problem where we cannot serialize an xref to an imported property's materializeForSet, since it was not created by the importer.
1 parent ff95d2d commit a360b45

File tree

12 files changed

+97
-4
lines changed

12 files changed

+97
-4
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,10 +2038,17 @@ class Verifier : public ASTWalker {
20382038
"Storage overrides but setter does not");
20392039
if (ASD->getMaterializeForSetFunc() &&
20402040
baseASD->getMaterializeForSetFunc() &&
2041-
baseASD->isSetterAccessibleFrom(ASD->getDeclContext()))
2042-
assert(ASD->getMaterializeForSetFunc()->getOverriddenDecl() ==
2043-
baseASD->getMaterializeForSetFunc() &&
2044-
"Storage override but materializeForSet does not");
2041+
baseASD->isSetterAccessibleFrom(ASD->getDeclContext())) {
2042+
if (baseASD->getMaterializeForSetFunc()->hasForcedStaticDispatch()) {
2043+
assert(ASD->getMaterializeForSetFunc()->getOverriddenDecl() == nullptr
2044+
&& "Forced static dispatch materializeForSet should not be "
2045+
"overridden");
2046+
} else {
2047+
assert(ASD->getMaterializeForSetFunc()->getOverriddenDecl() ==
2048+
baseASD->getMaterializeForSetFunc() &&
2049+
"Storage override but materializeForSet does not");
2050+
}
2051+
}
20452052
} else {
20462053
if (ASD->getGetter())
20472054
assert(!ASD->getGetter()->getOverriddenDecl() &&

lib/Sema/CodeSynthesis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@ static FuncDecl *addMaterializeForSet(AbstractStorageDecl *storage,
872872
// materializeForSet either.
873873
auto *baseMFS = baseASD->getMaterializeForSetFunc();
874874
if (baseMFS != nullptr &&
875+
!baseMFS->hasForcedStaticDispatch() &&
875876
baseASD->isSetterAccessibleFrom(storage->getDeclContext())) {
876877
materializeForSet->setOverriddenDecl(baseMFS);
877878
}

lib/Sema/TypeCheckDecl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6532,6 +6532,13 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
65326532
!baseASD->isSetterAccessibleFrom(overridingASD->getDeclContext()))
65336533
return;
65346534

6535+
// A materializeForSet for an override of storage with a
6536+
// forced static dispatch materializeForSet is not itself an
6537+
// override.
6538+
if (kind == AccessorKind::IsMaterializeForSet &&
6539+
baseAccessor->hasForcedStaticDispatch())
6540+
return;
6541+
65356542
// FIXME: Egregious hack to set an 'override' attribute.
65366543
if (!overridingAccessor->getAttrs().hasAttribute<OverrideAttr>()) {
65376544
auto loc = overridingASD->getOverrideLoc();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface Counter : NSObject
4+
@property(readwrite) int value;
5+
@end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Foundation
2+
import CounterFramework
3+
4+
public protocol CounterProtocol {
5+
var value: Int32 { get set }
6+
}
7+
8+
extension Counter : CounterProtocol {}
9+
10+
open class MyCounter : Counter {
11+
open override var value: Int32 { didSet { } }
12+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module CounterFramework {
2+
header "counter.h"
3+
export *
4+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: mkdir -p %t/onone %t/wmo
4+
// RUN: %target-build-swift -emit-module -emit-module-path %t/onone/library.swiftmodule -I %S/Inputs/ -module-name=library %S/Inputs/library.swift
5+
// RUN: %target-build-swift %S/main.swift -I %S/Inputs/ -I %t/onone/ -emit-ir > /dev/null
6+
7+
// RUN: %target-build-swift -emit-module -emit-module-path %t/wmo/library.swiftmodule -I %S/Inputs/ -module-name=library -wmo %S/Inputs/library.swift
8+
// RUN: %target-build-swift %S/main.swift -I %S/Inputs/ -I %t/wmo/ -emit-ir > /dev/null
9+
10+
// REQUIRES: objc_interop
11+
12+
import Foundation
13+
import library
14+
15+
class CustomCounter : MyCounter {
16+
override var value: Int32 { didSet { } }
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <Foundation/Foundation.h>
2+
3+
@interface Counter : NSObject
4+
@property(readwrite) int value;
5+
@end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Foundation
2+
import CounterFramework
3+
4+
public protocol CounterProtocol {
5+
var value: Int32 { get set }
6+
}
7+
8+
extension Counter : CounterProtocol {}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Foundation
2+
import CounterFramework
3+
4+
open class MyCounter : Counter {
5+
open override var value: Int32 { didSet { } }
6+
}

0 commit comments

Comments
 (0)