Skip to content

Commit 04ac33d

Browse files
committed
Sema: Fix order dependency in @objc inference from witnessed protocol requirement
If we haven't validated the declaration yet, the 'witnesses @objc requirement' check would immediately fail. Move the validateDecl() call to matchWitness() to fix this. Fixes <rdar://problem/49482328>, <https://bugs.swift.org/browse/SR-10257>.
1 parent 99eb35c commit 04ac33d

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ static ValueDecl *getStandinForAccessor(AbstractStorageDecl *witnessStorage,
426426

427427
RequirementMatch
428428
swift::matchWitness(
429-
TypeChecker &tc,
430429
DeclContext *dc, ValueDecl *req, ValueDecl *witness,
431430
llvm::function_ref<
432431
std::tuple<Optional<RequirementMatch>, Type, Type>(void)>
@@ -442,10 +441,17 @@ swift::matchWitness(
442441
if (req->getKind() != witness->getKind())
443442
return RequirementMatch(witness, MatchKind::KindConflict);
444443

444+
// If the witness has not been validated yet, do so now.
445+
if (!witness->hasValidSignature()) {
446+
auto &ctx = dc->getASTContext();
447+
ctx.getLazyResolver()->resolveDeclSignature(witness);
448+
}
449+
445450
// If the witness is invalid, record that and stop now.
446451
if (witness->isInvalid())
447452
return RequirementMatch(witness, MatchKind::WitnessInvalid);
448453

454+
// If we're currently validating the witness, bail out.
449455
if (!witness->hasValidSignature())
450456
return RequirementMatch(witness, MatchKind::Circularity);
451457

@@ -948,7 +954,7 @@ swift::matchWitness(TypeChecker &tc,
948954
return result;
949955
};
950956

951-
return matchWitness(tc, dc, req, witness, setup, matchTypes, finalize);
957+
return matchWitness(dc, req, witness, setup, matchTypes, finalize);
952958
}
953959

954960
static bool
@@ -1151,9 +1157,6 @@ bool WitnessChecker::findBestWitness(
11511157
continue;
11521158
}
11531159

1154-
if (!witness->hasValidSignature())
1155-
TC.validateDecl(witness);
1156-
11571160
auto match = matchWitness(TC, ReqEnvironmentCache, Proto, conformance, DC,
11581161
requirement, witness);
11591162
if (match.isViable()) {

lib/Sema/TypeCheckProtocol.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,6 @@ class AssociatedTypeInference {
897897
///
898898
/// \returns the result of performing the match.
899899
RequirementMatch matchWitness(
900-
TypeChecker &tc,
901900
DeclContext *dc, ValueDecl *req, ValueDecl *witness,
902901
llvm::function_ref<
903902
std::tuple<Optional<RequirementMatch>, Type, Type>(void)>

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitness(ValueDecl *req,
756756
// Match the witness. If we don't succeed, throw away the inference
757757
// information.
758758
// FIXME: A renamed match might be useful to retain for the failure case.
759-
if (matchWitness(tc, dc, req, witness, setup, matchTypes, finalize)
759+
if (matchWitness(dc, req, witness, setup, matchTypes, finalize)
760760
.Kind != MatchKind::ExactMatch) {
761761
inferred.Inferred.clear();
762762
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -print-ast %s | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
// This bug required an elaborate setup where isObjC() was checked prior
6+
// to validateDecl() getting called on a declaration. In this case, we
7+
// did not infer @objc from witnessed protocol requirements as required.
8+
//
9+
// https://bugs.swift.org/browse/SR-10257
10+
11+
@objc public protocol P {
12+
@objc optional func f()
13+
}
14+
15+
public class Other {
16+
// This triggers a walk over all nominals in the file, collecting
17+
// @objc members into the dynamic dispatch lookup table.
18+
let a = (Base() as AnyObject).g()
19+
}
20+
21+
@objc public class Base : P {
22+
@objc public func g() -> Int { return 0 }
23+
}
24+
25+
public class D : Base {
26+
// This method witnesses P.f() and so it should be @objc.
27+
//
28+
// CHECK-LABEL: @objc public func f()
29+
public func f() {}
30+
}
31+

0 commit comments

Comments
 (0)