Skip to content

Commit 3b36e26

Browse files
committed
prevent issues with null func ptrs and fix Distributed prorotocol test
1 parent 2cc4984 commit 3b36e26

File tree

2 files changed

+135
-44
lines changed

2 files changed

+135
-44
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,29 +2920,27 @@ bool ConformanceChecker::checkActorIsolation(
29202920
// If the distributed instance method is well-formed (passed checks) then it can
29212921
// witness this requirement. I.e. since checks to the distributed function
29222922
// passed, it can be called through this protocol.
2923-
if (witnessFunc && witnessFunc->isDistributed()) {
2924-
if (requirementFunc) {
2925-
// If the requirement was also a 'distributed func' we most definitely
2926-
// can witness it with our 'distributed func' witness.
2927-
if (requirementFunc->isDistributed()) {
2928-
return false;
2929-
}
2930-
if (requirementFunc->hasAsync() && requirementFunc->hasThrows()) {
2931-
return false;
2932-
}
2933-
2934-
// The witness was distributed, but the requirement func was not
2935-
// 'async throws', so we can suggest adding those to the protocol
2936-
int suggestAddingModifiers = 0;
2937-
if (!requirementFunc->hasAsync()) suggestAddingModifiers += 1;
2938-
if (!requirementFunc->hasThrows()) suggestAddingModifiers += 2;
2939-
requirementFunc->diagnose(diag::note_add_async_and_throws_to_decl,
2940-
witness->getName(),
2941-
suggestAddingModifiers,
2942-
witnessClass ? witnessClass->getName() :
2943-
nominal->getName());
2944-
// TODO(distributed): fixit inserts for the async/throws
2923+
if (requirementFunc && witnessFunc && witnessFunc->isDistributed()) {
2924+
// If the requirement was also a 'distributed func' we most definitely
2925+
// can witness it with our 'distributed func' witness.
2926+
if (requirementFunc->isDistributed()) {
2927+
return false;
2928+
}
2929+
if (requirementFunc->hasAsync() && requirementFunc->hasThrows()) {
2930+
return false;
29452931
}
2932+
2933+
// The witness was distributed, but the requirement func was not
2934+
// 'async throws', so we can suggest adding those to the protocol
2935+
int suggestAddingModifiers = 0;
2936+
if (!requirementFunc->hasAsync()) suggestAddingModifiers += 1;
2937+
if (!requirementFunc->hasThrows()) suggestAddingModifiers += 2;
2938+
requirementFunc->diagnose(diag::note_add_async_and_throws_to_decl,
2939+
witness->getName(),
2940+
suggestAddingModifiers,
2941+
witnessClass ? witnessClass->getName() :
2942+
nominal->getName());
2943+
// TODO(distributed): fixit inserts for the async/throws
29462944
}
29472945

29482946
// The witness definitely is distributed actor isolated,
@@ -2954,24 +2952,26 @@ bool ConformanceChecker::checkActorIsolation(
29542952

29552953
// witness is not 'distributed', if the requirement was though,
29562954
// then we definitely must mark the witness distributed as well.
2957-
if (requirementFunc) {
2958-
if (requirementFunc->isDistributed()) {
2959-
witness->diagnose(diag::note_add_distributed_to_decl,
2960-
witness->getName(),
2961-
witness->getDescriptiveKind())
2962-
.fixItInsert(witness->getAttributeInsertionLoc(true),
2963-
"distributed ");
2964-
requirement->diagnose(diag::note_distributed_requirement_defined_here,
2965-
requirement->getName());
2966-
} else if (requirementFunc->hasAsync() && requirementFunc->hasThrows()) {
2967-
assert(!requirementFunc->isDistributed());
2968-
// If the requirement is 'async throws' we can add 'distributed' to the
2969-
// distributed actor function to witness the requirement.
2970-
witness->diagnose(diag::note_add_distributed_to_decl,
2971-
witness->getName(), witness->getDescriptiveKind())
2972-
.fixItInsert(witness->getAttributeInsertionLoc(true),
2973-
"distributed ");
2974-
}
2955+
if (!requirementFunc) {
2956+
return true;
2957+
}
2958+
2959+
if (requirementFunc->isDistributed()) {
2960+
witness->diagnose(diag::note_add_distributed_to_decl,
2961+
witness->getName(),
2962+
witness->getDescriptiveKind())
2963+
.fixItInsert(witness->getAttributeInsertionLoc(true),
2964+
"distributed ");
2965+
requirement->diagnose(diag::note_distributed_requirement_defined_here,
2966+
requirement->getName());
2967+
} else if (requirementFunc->hasAsync() && requirementFunc->hasThrows()) {
2968+
assert(!requirementFunc->isDistributed());
2969+
// If the requirement is 'async throws' we can add 'distributed' to the
2970+
// distributed actor function to witness the requirement.
2971+
witness->diagnose(diag::note_add_distributed_to_decl,
2972+
witness->getName(), witness->getDescriptiveKind())
2973+
.fixItInsert(witness->getAttributeInsertionLoc(true),
2974+
"distributed ");
29752975
}
29762976

29772977
if (!requirementFunc->hasAsync() && !requirementFunc->isDistributed()) {

test/decl/protocol/special/DistributedActor.swift

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,36 @@ distributed actor D2 {
2020
}
2121

2222
distributed actor D3 {
23+
// expected-error@-1{{protocol 'DistributedActor' is broken; cannot derive conformance for type 'D3'}}
24+
// expected-error@-2{{protocol 'DistributedActor' is broken; cannot derive conformance for type 'D3'}} // FIXME(distributed): duplicate errors
25+
// expected-error@-3{{type 'D3' does not conform to protocol 'Identifiable'}}
26+
// expected-error@-4{{type 'D3' does not conform to protocol 'DistributedActor'}}
27+
// expected-error@-5{{type 'D3' does not conform to protocol 'DistributedActor'}}
28+
2329
var id: Int { 0 }
2430
// expected-error@-1{{property 'id' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}}
25-
// expected-error@-2{{invalid redeclaration of synthesized implementation for protocol requirement 'id'}}
31+
// expected-error@-2{{invalid redeclaration of synthesized property 'id'}}
32+
// expected-note@-3{{matching requirement 'id' to this declaration inferred associated type to 'Int'}}
2633
}
2734

35+
struct OtherActorIdentity: Sendable, Hashable, Codable {}
36+
2837
distributed actor D4 {
2938
// expected-error@-1{{actor 'D4' has no initializers}}
39+
// expected-error@-2{{type 'D4' does not conform to protocol 'DistributedActor'}} // FIXME(distributed): duplicated errors
40+
// expected-error@-3{{type 'D4' does not conform to protocol 'DistributedActor'}}
41+
// expected-error@-4{{protocol 'DistributedActor' is broken; cannot derive conformance for type 'D4'}} // FIXME(distributed): duplicated errors
42+
// expected-error@-5{{protocol 'DistributedActor' is broken; cannot derive conformance for type 'D4'}}
43+
// expected-error@-6{{type 'D4' does not conform to protocol 'Identifiable'}}
3044
let actorSystem: String
31-
// expected-error@-1{{invalid redeclaration of synthesized implementation for protocol requirement 'actorSystem'}}
45+
// expected-error@-1{{invalid redeclaration of synthesized property 'actorSystem'}}
3246
// expected-error@-2{{property 'actorSystem' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}}
3347
// expected-note@-3{{stored property 'actorSystem' without initial value prevents synthesized initializers}}
34-
let id: AnyActorIdentity
48+
let id: OtherActorIdentity
3549
// expected-error@-1{{property 'id' cannot be defined explicitly, as it conflicts with distributed actor synthesized stored property}}
36-
// expected-note@-2{{stored property 'id' without initial value prevents synthesized initializers}}
50+
// expected-error@-2{{invalid redeclaration of synthesized property 'id'}}
51+
// expected-note@-3{{stored property 'id' without initial value prevents synthesized initializers}}
52+
// expected-note@-4{{matching requirement 'id' to this declaration inferred associated type to 'OtherActorIdentity'}}
3753
}
3854

3955
protocol P1: DistributedActor {
@@ -57,3 +73,78 @@ func testConformance() {
5773
acceptDistributedActor(D1.self)
5874
acceptAnyActor(D1.self)
5975
}
76+
77+
78+
// ==== Fake Transport ---------------------------------------------------------
79+
80+
struct ActorAddress: Sendable, Hashable, Codable {
81+
let address: String
82+
init(parse address: String) {
83+
self.address = address
84+
}
85+
}
86+
87+
// global to track available IDs
88+
var nextID: Int = 1
89+
90+
struct FakeActorSystem: DistributedActorSystem {
91+
public typealias ActorID = ActorAddress
92+
public typealias Invocation = FakeInvocation
93+
public typealias SerializationRequirement = Codable
94+
95+
init() {
96+
print("Initialized new FakeActorSystem")
97+
}
98+
99+
public func resolve<Act>(id: ActorID, as actorType: Act.Type) throws -> Act?
100+
where Act: DistributedActor,
101+
Act.ID == ActorID {
102+
fatalError("not implemented:\(#function)")
103+
}
104+
105+
func assignID<Act>(_ actorType: Act.Type) -> ActorID
106+
where Act: DistributedActor {
107+
let id = ActorAddress(parse: "\(nextID)")
108+
nextID += 1
109+
print("assign type:\(actorType), id:\(id)")
110+
return id
111+
}
112+
113+
func actorReady<Act>(_ actor: Act)
114+
where Act: DistributedActor,
115+
Act.ID == ActorID {
116+
print("ready actor:\(actor), id:\(actor.id)")
117+
}
118+
119+
func resignID(_ id: ActorID) {
120+
print("resign id:\(id)")
121+
}
122+
123+
124+
public func makeInvocation() -> Invocation {
125+
.init()
126+
}
127+
}
128+
129+
public struct FakeInvocation: DistributedTargetInvocation {
130+
public typealias ArgumentDecoder = FakeArgumentDecoder
131+
public typealias SerializationRequirement = Codable
132+
133+
public mutating func recordGenericSubstitution<T>(mangledType: T.Type) throws {}
134+
public mutating func recordArgument<Argument: SerializationRequirement>(argument: Argument) throws {}
135+
public mutating func recordReturnType<R: SerializationRequirement>(mangledType: R.Type) throws {}
136+
public mutating func recordErrorType<E: Error>(mangledType: E.Type) throws {}
137+
public mutating func doneRecording() throws {}
138+
139+
// === Receiving / decoding -------------------------------------------------
140+
141+
public mutating func decodeGenericSubstitutions() throws -> [Any.Type] { [] }
142+
public mutating func argumentDecoder() -> FakeArgumentDecoder { .init() }
143+
public mutating func decodeReturnType() throws -> Any.Type? { nil }
144+
public mutating func decodeErrorType() throws -> Any.Type? { nil }
145+
146+
public struct FakeArgumentDecoder: DistributedTargetInvocationArgumentDecoder {
147+
public typealias SerializationRequirement = Codable
148+
}
149+
}
150+

0 commit comments

Comments
 (0)