Skip to content

Commit 43ce0df

Browse files
committed
Sema: Record a default witness for requirements with satisfied Obj-C siblings.
Rather than just skipping requirements with satisfied Obj-C siblings during `resolveValueWitnesses()`, proactively record a default witness for these requirements. This prevents lazy value witness resolution from giving the skipped requirements a default witness after the conformance is already marked complete, which causes an assertion to fail. Resolves rdar://119435253
1 parent 6e18ffe commit 43ce0df

File tree

3 files changed

+84
-18
lines changed

3 files changed

+84
-18
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4390,7 +4390,8 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43904390
// The compiler will reject actual uses.
43914391
auto Attrs = requirement->getAttrs();
43924392
if (Attrs.hasAttribute<OptionalAttr>() ||
4393-
Attrs.isUnavailable(getASTContext())) {
4393+
Attrs.isUnavailable(getASTContext()) ||
4394+
!shouldRecordMissingWitness(Proto, Conformance, requirement)) {
43944395
return ResolveWitnessResult::Missing;
43954396
}
43964397

@@ -4403,9 +4404,6 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
44034404
return ResolveWitnessResult::ExplicitFailed;
44044405
}
44054406

4406-
if (!shouldRecordMissingWitness(Proto, Conformance, requirement))
4407-
return ResolveWitnessResult::Missing;
4408-
44094407
if (!numViable) {
44104408
// Save the missing requirement for later diagnosis.
44114409
getASTContext().addDelayedMissingWitness(Conformance, {requirement, matches});
@@ -5109,13 +5107,13 @@ void ConformanceChecker::resolveValueWitnesses() {
51095107
// async-looking ObjC protocol method requirement into two Swift protocol
51105108
// requirements: an async version and a sync version. Exactly one of the two
51115109
// must be witnessed by the conformer.
5112-
if (!requirement->isImplicit() &&
5113-
getObjCRequirementSibling(
5114-
Proto, requirement, objcRequirementMap,
5115-
[this](AbstractFunctionDecl *cand) {
5116-
return !cand->getAttrs().hasAttribute<OptionalAttr>() &&
5117-
!cand->isImplicit() && this->Conformance->hasWitness(cand);
5118-
})) {
5110+
if (getObjCRequirementSibling(Proto, requirement, objcRequirementMap,
5111+
[this](AbstractFunctionDecl *cand) {
5112+
return static_cast<bool>(
5113+
this->Conformance->getWitness(cand));
5114+
})) {
5115+
recordOptionalWitness(requirement);
5116+
finalizeWitness();
51195117
continue;
51205118
}
51215119

test/ClangImporter/protocol-member-renaming.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ class Modern : NSObject, FooDelegate {
99
class PreMigration : NSObject, FooDelegate {
1010
func foo(_ foo: Foo, willConsumeObject object: Any) {}
1111
// expected-error@-1 {{'foo(_:willConsumeObject:)' has been renamed to 'foo(_:willConsume:)'}} {{24-41=willConsume}}
12-
// expected-error@-2 {{method 'foo(_:willConsumeObject:)' has different argument labels from those required by protocol 'FooDelegate' ('foo(_:willConsume:)')}} {{24-41=willConsume}}
1312
}
1413

1514
class OptionalButUnavailableImpl : OptionalButUnavailable {

test/Serialization/conformance-objc-async.swift

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// RUN: %empty-directory(%t)
22
// RUN: split-file %s %t
3-
// RUN: %target-swift-emit-module-interface(%t/Conformance.swiftinterface) -module-name Conformance -I %t %t/Conformance.swift
3+
// RUN: %target-swift-emit-module-interface(%t/Conformance.swiftinterface) -target %target-swift-abi-5.5-triple -module-name Conformance -I %t %t/Conformance.swift
4+
// RUN: %target-swift-emit-module-interface(%t/Conformance.swiftinterface) -target %target-swift-abi-5.5-triple -module-name Conformance -experimental-lazy-typecheck -I %t %t/Conformance.swift
45
// RUN: %target-swift-frontend -compile-module-from-interface %t/Conformance.swiftinterface -module-name Conformance -o /dev/null -I %t
56
// REQUIRES: objc_interop
6-
7-
// REQUIRES: rdar119435253
7+
// REQUIRES: concurrency
88

99
//--- module.modulemap
1010
module ObjCProto {
@@ -20,11 +20,80 @@ module ObjCProto {
2020
//--- Conformance.swift
2121
import ObjCProto
2222

23-
public final class ConformsToDoableWithCompletionHandler: Doable {
23+
public final class DoableWithCompletionHandler: Doable {
24+
// Matches synchronous requirement
2425
public func doIt(completion: @escaping () -> Void) {}
2526
}
2627

27-
@available(SwiftStdlib 5.5, *)
28-
public final class ConformsToDoableWithAsync:Doable {
28+
public final class DoableWithAsync: Doable {
29+
// Matches async requirement
30+
public func doIt() async {}
31+
}
32+
33+
public final class DoableWithCompletionHandlerAndAsyncCandidate: Doable {
34+
// Matches synchronous requirement
35+
public func doIt(completion: @escaping () -> Void) {}
36+
37+
// Near-miss for async requirement
38+
public func doIt() async -> Int {}
39+
}
40+
41+
public final class DoableWithCompletionHandlerAndAsyncCandidate2: Doable {
42+
// Near-miss for async requirement
43+
public func doIt() async -> Int {}
44+
45+
// Matches synchronous requirement
46+
public func doIt(completion: @escaping () -> Void) {}
47+
}
48+
49+
public final class DoableWithCompletionHandlerAndMultipleAsyncCandidates: Doable {
50+
// Matches synchronous requirement
51+
public func doIt(completion: @escaping () -> Void) {}
52+
53+
// Multiple near-misses for async requirement
54+
public func doIt() async -> Int {}
55+
public func doIt() async -> Double {}
56+
}
57+
58+
public final class DoableWithCompletionHandlerAndMultipleAsyncCandidates2: Doable {
59+
// Multiple near-misses for async requirement
60+
public func doIt() async -> Int {}
61+
public func doIt() async -> Double {}
62+
63+
// Matches synchronous requirement
64+
public func doIt(completion: @escaping () -> Void) {}
65+
}
66+
67+
public final class DoableWithAsyncAndCompletionHandlerCandidate: Doable {
68+
// Matches async requirement
69+
public func doIt() async {}
70+
71+
// Near-miss for synchronous requirement
72+
public func doIt(reply: @escaping () -> Void) {}
73+
}
74+
75+
public final class DoableWithAsyncAndCompletionHandlerCandidate2: Doable {
76+
// Near-miss for synchronous requirement
77+
public func doIt(reply: @escaping () -> Void) {}
78+
79+
// Matches async requirement
80+
public func doIt() async {}
81+
}
82+
83+
public final class DoableWithAsyncAndMultipleCompletionHandlerCandidates: Doable {
84+
// Matches async requirement
85+
public func doIt() async {}
86+
87+
// Multiple near-misses for synchronous requirement
88+
public func doIt(reply: @escaping () -> Void) {}
89+
public func doIt(otherReply: @escaping () -> Void) {}
90+
}
91+
92+
public final class DoableWithAsyncAndMultipleCompletionHandlerCandidates2: Doable {
93+
// Multiple near-misses for synchronous requirement
94+
public func doIt(otherReply: @escaping () -> Void) {}
95+
public func doIt(reply: @escaping () -> Void) {}
96+
97+
// Matches async requirement
2998
public func doIt() async {}
3099
}

0 commit comments

Comments
 (0)