Skip to content

Commit 7dc1e1e

Browse files
authored
Merge pull request #11242 from slavapestov/ambiguous-requirement-witness-subclass-existential-4.0
Sema: Fix requirement/witness disambiguation for subclass existentials [4.0]
2 parents 12b5fd7 + 94b02a0 commit 7dc1e1e

File tree

3 files changed

+44
-6
lines changed

3 files changed

+44
-6
lines changed

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//
1717
//===----------------------------------------------------------------------===//
1818
#include "TypeChecker.h"
19+
#include "swift/AST/ExistentialLayout.h"
1920
#include "swift/AST/Initializer.h"
2021
#include "swift/AST/NameLookup.h"
2122
#include "swift/AST/ProtocolConformance.h"
@@ -120,27 +121,48 @@ namespace {
120121
if (!Options.contains(NameLookupFlags::ProtocolMembers) ||
121122
!isa<ProtocolDecl>(foundDC) ||
122123
isa<GenericTypeParamDecl>(found) ||
123-
(isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator()) ||
124-
foundInType->isAnyExistentialType()) {
124+
(isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator())) {
125125
addResult(found);
126126
return;
127127
}
128128

129129
assert(isa<ProtocolDecl>(foundDC));
130130

131+
auto conformingType = foundInType;
132+
133+
// When performing a lookup on a subclass existential, we might
134+
// find a member of the class that witnesses a requirement on a
135+
// protocol that the class conforms to.
136+
//
137+
// Since subclass existentials don't normally conform to protocols,
138+
// pull out the superclass instead, and use that below.
139+
if (foundInType->isExistentialType()) {
140+
auto layout = foundInType->getExistentialLayout();
141+
if (layout.superclass)
142+
conformingType = layout.superclass;
143+
}
144+
131145
// If we found something within the protocol itself, and our
132146
// search began somewhere that is not in a protocol or extension
133147
// thereof, remap this declaration to the witness.
134148
if (foundInType->is<ArchetypeType>() ||
149+
foundInType->isExistentialType() ||
135150
Options.contains(NameLookupFlags::PerformConformanceCheck)) {
136151
// Dig out the protocol conformance.
137-
auto conformance = TC.conformsToProtocol(foundInType, foundProto, DC,
152+
auto conformance = TC.conformsToProtocol(conformingType, foundProto, DC,
138153
conformanceOptions);
139-
if (!conformance)
154+
if (!conformance) {
155+
// If there's no conformance, we have an existential
156+
// and we found a member from one of the protocols, and
157+
// not a class constraint if any.
158+
assert(foundInType->isExistentialType());
159+
addResult(found);
140160
return;
161+
}
141162

142163
if (conformance->isAbstract()) {
143-
assert(foundInType->is<ArchetypeType>());
164+
assert(foundInType->is<ArchetypeType>() ||
165+
foundInType->isExistentialType());
144166
addResult(found);
145167
return;
146168
}
@@ -161,6 +183,10 @@ namespace {
161183

162184
// FIXME: the "isa<ProtocolDecl>()" check will be wrong for
163185
// default implementations in protocols.
186+
//
187+
// If we have an imported conformance or the witness could
188+
// not be deserialized, getWitnessDecl() will just return
189+
// the requirement, so just drop the lookup result here.
164190
if (witness && !isa<ProtocolDecl>(witness->getDeclContext()))
165191
addResult(witness);
166192

test/ClangImporter/subclass_existentials.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ class OldSwiftLaundryService : NSLaundry {
3535
return g!
3636
}
3737
}
38+
39+
// Make sure the method lookup is not ambiguous
40+
41+
_ = Coat.fashionStatement.wear()

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1086,13 +1086,21 @@ typedef enum __attribute__((ns_error_domain(FictionalServerErrorDomain))) Fictio
10861086
FictionalServerErrorMeltedDown = 1
10871087
} FictionalServerErrorCode;
10881088

1089+
@protocol Wearable
1090+
- (void)wear;
1091+
@end
1092+
10891093
@protocol Garment
10901094
@end
10911095

10921096
@protocol Cotton
10931097
@end
10941098

1095-
@interface Coat
1099+
@interface Coat : NSObject<Wearable>
1100+
1101+
- (void)wear;
1102+
@property (class) Coat <Wearable> *fashionStatement;
1103+
10961104
@end
10971105

10981106
@protocol NSLaundry

0 commit comments

Comments
 (0)