Skip to content

Commit b556cb5

Browse files
committed
IDE: Refactor SynthesizedExtensionAnalyzer to use Requirement::isSatisfied()
1 parent 73deb7e commit b556cb5

File tree

4 files changed

+225
-173
lines changed

4 files changed

+225
-173
lines changed

lib/IDE/IDETypeChecking.cpp

Lines changed: 34 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Module.h"
2323
#include "swift/AST/NameLookup.h"
2424
#include "swift/AST/ProtocolConformance.h"
25+
#include "swift/AST/Requirement.h"
2526
#include "swift/AST/SourceFile.h"
2627
#include "swift/AST/Types.h"
2728
#include "swift/Sema/IDETypeChecking.h"
@@ -169,13 +170,13 @@ struct SynthesizedExtensionAnalyzer::Implementation {
169170
bool Unmergable;
170171
unsigned InheritsCount;
171172
std::set<Requirement> Requirements;
172-
void addRequirement(GenericSignature GenericSig,
173-
Type First, Type Second, RequirementKind Kind) {
174-
CanType CanFirst = GenericSig->getCanonicalTypeInContext(First);
175-
CanType CanSecond;
176-
if (Second) CanSecond = GenericSig->getCanonicalTypeInContext(Second);
173+
void addRequirement(GenericSignature GenericSig, swift::Requirement Req) {
174+
auto First = Req.getFirstType();
175+
auto CanFirst = GenericSig->getCanonicalTypeInContext(First);
176+
auto Second = Req.getSecondType();
177+
auto CanSecond = GenericSig->getCanonicalTypeInContext(Second);
177178

178-
Requirements.insert({First, Second, Kind, CanFirst, CanSecond});
179+
Requirements.insert({First, Second, Req.getKind(), CanFirst, CanSecond});
179180
}
180181
bool operator== (const ExtensionMergeInfo& Another) const {
181182
// Trivially unmergeable.
@@ -289,84 +290,53 @@ struct SynthesizedExtensionAnalyzer::Implementation {
289290
ProtocolDecl *BaseProto = OwningExt->getInnermostDeclContext()
290291
->getSelfProtocolDecl();
291292
for (auto Req : Reqs) {
292-
auto Kind = Req.getKind();
293-
294-
// FIXME: Could do something here
295-
if (Kind == RequirementKind::Layout)
293+
// FIXME: Don't skip layout requirements.
294+
if (Req.getKind() == RequirementKind::Layout)
296295
continue;
297296

298-
Type First = Req.getFirstType();
299-
Type Second = Req.getSecondType();
300-
301297
// Skip protocol's Self : <Protocol> requirement.
302298
if (BaseProto &&
303299
Req.getKind() == RequirementKind::Conformance &&
304-
First->isEqual(BaseProto->getSelfInterfaceType()) &&
305-
Second->getAnyNominal() == BaseProto)
300+
Req.getFirstType()->isEqual(BaseProto->getSelfInterfaceType()) &&
301+
Req.getProtocolDecl() == BaseProto)
306302
continue;
307303

308304
if (!BaseType->isExistentialType()) {
309305
// Apply any substitutions we need to map the requirements from a
310306
// a protocol extension to an extension on the conforming type.
311-
First = First.subst(subMap);
312-
Second = Second.subst(subMap);
313-
314-
if (First->hasError() || Second->hasError()) {
307+
auto SubstReq = Req.subst(subMap);
308+
if (!SubstReq) {
315309
// Substitution with interface type bases can only fail
316310
// if a concrete type fails to conform to a protocol.
317311
// In this case, just give up on the extension altogether.
318312
return true;
319313
}
320-
}
321314

322-
assert(!First->hasArchetype() && !Second->hasArchetype());
323-
switch (Kind) {
324-
case RequirementKind::Conformance: {
325-
auto *M = DC->getParentModule();
326-
auto *Proto = Second->castTo<ProtocolType>()->getDecl();
327-
if (!First->isTypeParameter() &&
328-
M->conformsToProtocol(First, Proto).isInvalid())
329-
return true;
330-
if (M->conformsToProtocol(First, Proto).isInvalid())
331-
MergeInfo.addRequirement(GenericSig, First, Second, Kind);
332-
break;
315+
Req = *SubstReq;
333316
}
334317

335-
case RequirementKind::Superclass:
336-
// If the subject type of the requirement is still a type parameter,
337-
// we need to check if the contextual type could possibly be bound to
338-
// the superclass. If not, this extension isn't applicable.
339-
if (First->isTypeParameter()) {
340-
if (!Target->mapTypeIntoContext(First)->isBindableTo(
341-
Target->mapTypeIntoContext(Second))) {
342-
return true;
343-
}
344-
MergeInfo.addRequirement(GenericSig, First, Second, Kind);
345-
break;
346-
}
347-
348-
// If we've substituted in a concrete type for the subject, we can
349-
// check for an exact superclass match, and disregard the extension if
350-
// it missed.
351-
// FIXME: What if it ends being something like `C<U> : C<Int>`?
352-
// Arguably we should allow that to be mirrored with a U == Int
353-
// constraint.
354-
if (!Second->isExactSuperclassOf(First))
355-
return true;
356-
357-
break;
358-
359-
case RequirementKind::SameType:
360-
if (!First->isBindableTo(Second) &&
361-
!Second->isBindableTo(First)) {
318+
assert(!Req.getFirstType()->hasArchetype());
319+
assert(!Req.getSecondType()->hasArchetype());
320+
321+
auto *M = DC->getParentModule();
322+
auto SubstReq = Req.subst(
323+
[&](Type type) -> Type {
324+
if (type->isTypeParameter())
325+
return Target->mapTypeIntoContext(type);
326+
327+
return type;
328+
},
329+
LookUpConformanceInModule(M));
330+
if (!SubstReq)
331+
return true;
332+
333+
// FIXME: Need to handle conditional requirements here!
334+
ArrayRef<Requirement> conditionalRequirements;
335+
if (!SubstReq->isSatisfied(conditionalRequirements)) {
336+
if (!SubstReq->canBeSatisfied())
362337
return true;
363-
} else if (!First->isEqual(Second)) {
364-
MergeInfo.addRequirement(GenericSig, First, Second, Kind);
365-
}
366-
break;
367338

368-
case RequirementKind::Layout:
369-
llvm_unreachable("Handled above");
339+
MergeInfo.addRequirement(GenericSig, Req);
370340
}
371341
}
372342
return false;

test/IDE/print_synthesized_extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ extension C : P8 {}
393393
public class F<T : D> {}
394394
extension F : P8 {}
395395

396-
// CHECK16: <synthesized>extension <ref:Class>F</ref> where <ref:GenericTypeParam>T</ref> : <ref:Class>D</ref> {
396+
// CHECK16: <decl:Class>public class <loc>F<<decl:GenericTypeParam>T</decl>></loc> where <ref:GenericTypeParam>T</ref> : <ref:module>print_synthesized_extensions</ref>.<ref:Class>D</ref> {</decl>
397397
// CHECK16-NEXT: <decl:Func>public func <loc>bar()</loc></decl>
398398
// CHECK16-NEXT: }</synthesized>
399399

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module-path %t/print_synthesized_extensions_superclass.swiftmodule -emit-module-doc -emit-module-doc-path %t/print_synthesized_extensions_superclass.swiftdoc %s
3+
// RUN: %target-swift-ide-test -print-module -synthesize-extension -print-interface -no-empty-line-between-members -module-to-print=print_synthesized_extensions_superclass -I %t -source-filename=%s | %FileCheck %s
4+
5+
public class Base {}
6+
public class Middle<T> : Base {}
7+
public class Most : Middle<Int> {}
8+
9+
public protocol P {
10+
associatedtype T
11+
associatedtype U
12+
}
13+
14+
public extension P where T : Base {
15+
func withBase() {}
16+
}
17+
18+
public extension P where T : Middle<U> {
19+
func withMiddleAbstract() {}
20+
}
21+
22+
public extension P where T : Middle<Int> {
23+
func withMiddleConcrete() {}
24+
}
25+
26+
public extension P where T : Most {
27+
func withMost() {}
28+
}
29+
30+
// CHECK-LABEL: public struct S1 : print_synthesized_extensions_superclass.P {
31+
// CHECK-NEXT: public typealias T = print_synthesized_extensions_superclass.Base
32+
// CHECK-NEXT: public typealias U = Int
33+
// CHECK-NEXT: public func withBase()
34+
// CHECk-NEXT: }
35+
36+
public struct S1 : P {
37+
public typealias T = Base
38+
public typealias U = Int
39+
}
40+
41+
// CHECK-LABEL: public struct S2 : print_synthesized_extensions_superclass.P {
42+
// CHECK-NEXT: public typealias T = print_synthesized_extensions_superclass.Middle<Int>
43+
// CHECK-NEXT: public typealias U = Int
44+
// CHECK-NEXT: public func withBase()
45+
// CHECk-NEXT: public func withMiddleAbstract()
46+
// CHECk-NEXT: public func withMiddleConcrete()
47+
// CHECk-NEXT: }
48+
49+
public struct S2 : P {
50+
public typealias T = Middle<Int>
51+
public typealias U = Int
52+
}
53+
54+
// CHECK-LABEL: public struct S3 : print_synthesized_extensions_superclass.P {
55+
// CHECK-NEXT: public typealias T = print_synthesized_extensions_superclass.Middle<String>
56+
// CHECK-NEXT: public typealias U = String
57+
// CHECK-NEXT: public func withBase()
58+
// CHECK-NEXT: public func withMiddleAbstract()
59+
// CHECK-NEXT: }
60+
61+
public struct S3 : P {
62+
public typealias T = Middle<String>
63+
public typealias U = String
64+
}
65+
66+
// CHECK-LABEL: public struct S4 : print_synthesized_extensions_superclass.P {
67+
// CHECK-NEXT: public typealias T = print_synthesized_extensions_superclass.Most
68+
// CHECK-NEXT: public typealias U = Int
69+
// CHECK-NEXT: public func withBase()
70+
// CHECK-NEXT: public func withMiddleAbstract()
71+
// CHECK-NEXT: public func withMiddleConcrete()
72+
// CHECK-NEXT: public func withMost()
73+
// CHECK-NEXT: }
74+
75+
public struct S4 : P {
76+
public typealias T = Most
77+
public typealias U = Int
78+
}
79+
80+
// CHECK-LABEL: public struct S5 : print_synthesized_extensions_superclass.P {
81+
// CHECK-NEXT: public typealias T = print_synthesized_extensions_superclass.Most
82+
// CHECK-NEXT: public typealias U = String
83+
// CHECK-NEXT: public func withBase()
84+
// CHECK-NEXT: public func withMiddleConcrete()
85+
// CHECK-NEXT: public func withMost()
86+
// CHECK-NEXT: }
87+
88+
public struct S5 : P {
89+
public typealias T = Most
90+
public typealias U = String
91+
}
92+
93+
// CHECK-LABEL: public struct S6<T, U> : print_synthesized_extensions_superclass.P where T : print_synthesized_extensions_superclass.Base {
94+
// CHECK-NEXT: public func withBase()
95+
// CHECK-NEXT: }
96+
97+
// CHECK-LABEL: extension S6 where T : Middle<U> {
98+
// CHECK-NEXT: public func withMiddleAbstract()
99+
// CHECK-NEXT: }
100+
101+
// CHECK-LABEL: extension S6 where T : Middle<Int> {
102+
// CHECK-NEXT: public func withMiddleConcrete()
103+
// CHECK-NEXT: }
104+
105+
// CHECK-LABEL: extension S6 where T : Most {
106+
// CHECK-NEXT: public func withMost()
107+
// CHECK-NEXT: }
108+
109+
public struct S6<T, U> : P where T : Base {}
110+
111+
// CHECK-LABEL: public struct S7<T, U> : print_synthesized_extensions_superclass.P where T : print_synthesized_extensions_superclass.Middle<U> {
112+
// CHECK-NEXT: public func withBase()
113+
// CHECK-NEXT: public func withMiddleAbstract()
114+
// CHECK-NEXT: }
115+
116+
// CHECK-LABEL: extension S7 where T : Middle<Int> {
117+
// CHECK-NEXT: public func withMiddleConcrete()
118+
// CHECK-NEXT: }
119+
120+
// CHECK-LABEL: extension S7 where T : Most {
121+
// CHECK-NEXT: public func withMost()
122+
// CHECK-NEXT: }
123+
124+
public struct S7<T, U> : P where T : Middle<U> {}
125+
126+
// CHECK-LABEL: public struct S8<T, U> : print_synthesized_extensions_superclass.P where T : print_synthesized_extensions_superclass.Most {
127+
// CHECK-NEXT: public func withBase()
128+
// CHECK-NEXT: public func withMiddleConcrete()
129+
// CHECK-NEXT: public func withMost()
130+
// CHECK-NEXT: }
131+
132+
public struct S8<T, U> : P where T : Most {}

0 commit comments

Comments
 (0)