Skip to content

Commit 1b18b82

Browse files
authored
Merge pull request #11241 from slavapestov/ambiguous-requirement-witness-subclass-existential
Sema: Fix requirement/witness disambiguation for subclass existentials
2 parents 781b133 + ac8e037 commit 1b18b82

File tree

4 files changed

+45
-11
lines changed

4 files changed

+45
-11
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8529,7 +8529,7 @@ bool FailureDiagnosis::diagnoseMemberFailures(
85298529
}
85308530

85318531
if (result.UnviableCandidates.empty() && isInitializer &&
8532-
!baseObjTy->is<MetatypeType>()) {
8532+
!baseObjTy->is<AnyMetatypeType>()) {
85338533
if (auto ctorRef = dyn_cast<UnresolvedDotExpr>(E)) {
85348534
// Diagnose 'super.init', which can only appear inside another
85358535
// initializer, specially.

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 31 additions & 9 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"
@@ -121,35 +122,52 @@ namespace {
121122
if (!Options.contains(NameLookupFlags::ProtocolMembers) ||
122123
!isa<ProtocolDecl>(foundDC) ||
123124
isa<GenericTypeParamDecl>(found) ||
124-
(isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator()) ||
125-
foundInType->isAnyExistentialType()) {
125+
(isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator())) {
126126
addResult(found);
127127
return;
128128
}
129129

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

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

143164
if (conformance->isAbstract()) {
144-
assert(foundInType->is<ArchetypeType>());
165+
assert(foundInType->is<ArchetypeType>() ||
166+
foundInType->isExistentialType());
145167
addResult(found);
146168
return;
147169
}
148170

149-
// If we're validating the protocol recursively, bail out.
150-
if (!foundProto->hasValidSignature())
151-
return;
152-
153171
// Dig out the witness.
154172
ValueDecl *witness = nullptr;
155173
auto concrete = conformance->getConcrete();
@@ -162,6 +180,10 @@ namespace {
162180

163181
// FIXME: the "isa<ProtocolDecl>()" check will be wrong for
164182
// default implementations in protocols.
183+
//
184+
// If we have an imported conformance or the witness could
185+
// not be deserialized, getWitnessDecl() will just return
186+
// the requirement, so just drop the lookup result here.
165187
if (witness && !isa<ProtocolDecl>(witness->getDeclContext()))
166188
addResult(witness);
167189

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
@@ -1098,13 +1098,21 @@ typedef enum __attribute__((ns_error_domain(FictionalServerErrorDomain))) Fictio
10981098
FictionalServerErrorMeltedDown = 1
10991099
} FictionalServerErrorCode;
11001100

1101+
@protocol Wearable
1102+
- (void)wear;
1103+
@end
1104+
11011105
@protocol Garment
11021106
@end
11031107

11041108
@protocol Cotton
11051109
@end
11061110

1107-
@interface Coat
1111+
@interface Coat : NSObject<Wearable>
1112+
1113+
- (void)wear;
1114+
@property (class) Coat <Wearable> *fashionStatement;
1115+
11081116
@end
11091117

11101118
@protocol NSLaundry

0 commit comments

Comments
 (0)