Skip to content

Commit 0f2da21

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 a0c0146 commit 0f2da21

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
@@ -2097,10 +2097,17 @@ class Verifier : public ASTWalker {
20972097
"Storage overrides but setter does not");
20982098
if (ASD->getMaterializeForSetFunc() &&
20992099
baseASD->getMaterializeForSetFunc() &&
2100-
baseASD->isSetterAccessibleFrom(ASD->getDeclContext()))
2101-
assert(ASD->getMaterializeForSetFunc()->getOverriddenDecl() ==
2102-
baseASD->getMaterializeForSetFunc() &&
2103-
"Storage override but materializeForSet does not");
2100+
baseASD->isSetterAccessibleFrom(ASD->getDeclContext())) {
2101+
if (baseASD->getMaterializeForSetFunc()->hasForcedStaticDispatch()) {
2102+
assert(ASD->getMaterializeForSetFunc()->getOverriddenDecl() == nullptr
2103+
&& "Forced static dispatch materializeForSet should not be "
2104+
"overridden");
2105+
} else {
2106+
assert(ASD->getMaterializeForSetFunc()->getOverriddenDecl() ==
2107+
baseASD->getMaterializeForSetFunc() &&
2108+
"Storage override but materializeForSet does not");
2109+
}
2110+
}
21042111
} else {
21052112
if (ASD->getGetter())
21062113
assert(!ASD->getGetter()->getOverriddenDecl() &&

lib/Sema/CodeSynthesis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,7 @@ static FuncDecl *addMaterializeForSet(AbstractStorageDecl *storage,
857857
// materializeForSet either.
858858
auto *baseMFS = baseASD->getMaterializeForSetFunc();
859859
if (baseMFS != nullptr &&
860+
!baseMFS->hasForcedStaticDispatch() &&
860861
baseASD->isSetterAccessibleFrom(storage->getDeclContext())) {
861862
materializeForSet->setOverriddenDecl(baseMFS);
862863
}

lib/Sema/TypeCheckDecl.cpp

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

6708+
// A materializeForSet for an override of storage with a
6709+
// forced static dispatch materializeForSet is not itself an
6710+
// override.
6711+
if (kind == AccessorKind::IsMaterializeForSet &&
6712+
baseAccessor->hasForcedStaticDispatch())
6713+
return;
6714+
67086715
// FIXME: Egregious hack to set an 'override' attribute.
67096716
if (!overridingAccessor->getAttrs().hasAttribute<OverrideAttr>()) {
67106717
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+
}
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/library1.swift %S/Inputs/library2.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/library1.swift %S/Inputs/library2.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+
}

0 commit comments

Comments
 (0)