IDE: Fix my own lazyness in SynthesizedExtensionAnalyzer::Implementation::isApplicable()

This routine was never properly updated to handle layout requirements, conditional conformances,
or parameter packs. Let's clear out the FIXMEs and do things properly here.

Fixes https://github.com/swiftlang/swift/issues/76561
This commit is contained in:
Slava Pestov
2024-10-10 12:31:46 -04:00
parent ffaee52eb4
commit f751d500bf
2 changed files with 58 additions and 57 deletions

View File

@@ -191,22 +191,24 @@ struct SynthesizedExtensionAnalyzer::Implementation {
struct ExtensionMergeInfo {
struct Requirement {
Type First;
Type Second;
RequirementKind Kind;
CanType CanFirst;
CanType CanSecond;
swift::Requirement Req;
bool operator< (const Requirement& Rhs) const {
if (Kind != Rhs.Kind)
return Kind < Rhs.Kind;
else if (CanFirst != Rhs.CanFirst)
return CanFirst < Rhs.CanFirst;
else
return CanSecond < Rhs.CanSecond;
bool operator<(const Requirement& Rhs) const {
if (auto result = unsigned(Req.getKind()) - unsigned(Rhs.Req.getKind())) {
return result < 0;
} else if (!Req.getFirstType()->isEqual(Rhs.Req.getFirstType())) {
return (Req.getFirstType()->getCanonicalType() <
Rhs.Req.getFirstType()->getCanonicalType());
} else if (Req.getKind() != RequirementKind::Layout) {
return (Req.getSecondType()->getCanonicalType() <
Rhs.Req.getSecondType()->getCanonicalType());
}
return false;
}
bool operator== (const Requirement& Rhs) const {
return (!(*this < Rhs)) && (!(Rhs < *this));
return Req.getCanonical() == Rhs.Req.getCanonical();
}
};
@@ -214,12 +216,7 @@ struct SynthesizedExtensionAnalyzer::Implementation {
unsigned InheritsCount;
std::set<Requirement> Requirements;
void addRequirement(swift::Requirement Req) {
auto First = Req.getFirstType();
auto CanFirst = First->getCanonicalType();
auto Second = Req.getSecondType();
auto CanSecond = Second->getCanonicalType();
Requirements.insert({First, Second, Req.getKind(), CanFirst, CanSecond});
Requirements.insert({Req});
}
bool operator== (const ExtensionMergeInfo& Another) const {
// Trivially unmergeable.
@@ -333,10 +330,6 @@ struct SynthesizedExtensionAnalyzer::Implementation {
ProtocolDecl *BaseProto = OwningExt->getInnermostDeclContext()
->getSelfProtocolDecl();
for (auto Req : Reqs) {
// FIXME: Don't skip layout requirements.
if (Req.getKind() == RequirementKind::Layout)
continue;
// Skip protocol's Self : <Protocol> requirement.
if (BaseProto &&
Req.getKind() == RequirementKind::Conformance &&
@@ -357,40 +350,35 @@ struct SynthesizedExtensionAnalyzer::Implementation {
}
assert(!Req.getFirstType()->hasArchetype());
assert(!Req.getSecondType()->hasArchetype());
auto SubstReq = Req.subst(
[&](Type type) -> Type {
if (type->isTypeParameter())
return Target->mapTypeIntoContext(type);
return type;
},
LookUpConformanceInModule());
if (Req.getKind() != RequirementKind::Layout)
assert(!Req.getSecondType()->hasArchetype());
auto *env = Target->getGenericEnvironment();
SmallVector<Requirement, 2> subReqs;
switch (SubstReq.checkRequirement(subReqs)) {
case CheckRequirementResult::Success:
break;
subReqs.push_back(
Req.subst(
QueryInterfaceTypeSubstitutions(env),
LookUpConformanceInModule(),
SubstFlags::PreservePackExpansionLevel));
case CheckRequirementResult::ConditionalConformance:
// FIXME: Need to handle conditional requirements here!
break;
while (!subReqs.empty()) {
auto req = subReqs.pop_back_val();
switch (req.checkRequirement(subReqs)) {
case CheckRequirementResult::Success:
case CheckRequirementResult::PackRequirement:
case CheckRequirementResult::ConditionalConformance:
break;
case CheckRequirementResult::PackRequirement:
// FIXME
assert(false && "Refactor this");
return true;
case CheckRequirementResult::SubstitutionFailure:
return true;
case CheckRequirementResult::RequirementFailure:
if (!SubstReq.canBeSatisfied())
case CheckRequirementResult::SubstitutionFailure:
return true;
MergeInfo.addRequirement(Req);
break;
case CheckRequirementResult::RequirementFailure:
if (!req.canBeSatisfied())
return true;
MergeInfo.addRequirement(Req);
break;
}
}
}
return false;

View File

@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module-path %t/print_synthesized_extensions.swiftmodule -emit-module-doc -emit-module-doc-path %t/print_synthesized_extensions.swiftdoc %s
// RUN: %target-swift-ide-test -print-module -annotate-print -synthesize-extension -print-interface -no-empty-line-between-members -module-to-print=print_synthesized_extensions -I %t -source-filename=%s > %t.syn.txt
// RUN: %target-swift-frontend -target %target-swift-5.9-abi-triple -emit-module-path %t/print_synthesized_extensions.swiftmodule -emit-module-doc -emit-module-doc-path %t/print_synthesized_extensions.swiftdoc %s
// RUN: %target-swift-ide-test -annotate-print -print-module -synthesize-extension -print-interface -no-empty-line-between-members -module-to-print=print_synthesized_extensions -I %t -source-filename=%s -target=%target-swift-5.9-abi-triple > %t.syn.txt
// RUN: %FileCheck %s -check-prefix=CHECK1 < %t.syn.txt
// RUN: %FileCheck %s -check-prefix=CHECK2 < %t.syn.txt
// RUN: %FileCheck %s -check-prefix=CHECK3 < %t.syn.txt
@@ -17,6 +17,7 @@
// RUN: %FileCheck %s -check-prefix=CHECK14 < %t.syn.txt
// RUN: %FileCheck %s -check-prefix=CHECK15 < %t.syn.txt
// RUN: %FileCheck %s -check-prefix=CHECK16 < %t.syn.txt
// RUN: %FileCheck %s -check-prefix=CHECK17 < %t.syn.txt
public protocol P1 {
associatedtype T1
@@ -312,8 +313,6 @@ extension S13 : P5 {
// CHECK11-NEXT: public func <loc>foo3()</loc></decl>
// CHECK11-NEXT: <decl:Func>/// This is picked
// CHECK11-NEXT: public func <loc>foo4()</loc></decl>
// CHECK11-NEXT: <decl:Func>/// This should not crash
// CHECK11-NEXT: public func <loc>foo5()</loc></decl>
// CHECK11-NEXT: }</synthesized>
// CHECK12: <decl:Protocol>public protocol <loc>P6</loc> {
@@ -338,8 +337,6 @@ extension S13 : P5 {
// CHECK14-NEXT: public func <loc>foo3()</loc></decl>
// CHECK14-NEXT: <decl:Func>/// This is picked
// CHECK14-NEXT: public func <loc>foo4()</loc></decl>
// CHECK14-NEXT: <decl:Func>/// This should not crash
// CHECK14-NEXT: public func <loc>foo5()</loc></decl>
// CHECK14-NEXT: }</synthesized>
// rdar://76868074: Make sure we print the extensions for C.
@@ -398,3 +395,19 @@ extension F : P8 {}
// CHECK16-NEXT: }</synthesized>
// CHECK16-NOT: <synthesized>extension <ref:Class>F</ref> where <ref:GenericTypeParam>T</ref> : <ref:module>print_synthesized_extensions</ref>.<ref:Class>E</ref> {
// Parameter packs
public protocol P14 {}
extension P14 {
public func foo<each T: Equatable>(_: repeat each T) {}
}
public struct S14<each T: Equatable> {}
extension S14 : P14 where repeat each T: Hashable {}
// CHECK17: <synthesized>extension <ref:Struct>S14</ref> {
// CHECK17-NEXT: <decl:Func>public func <loc>foo<each <ref:GenericTypeParam>T</ref>>(<decl:Param>_: repeat each <ref:GenericTypeParam>T</ref></decl>)</loc> where Pack{repeat each <ref:GenericTypeParam>T</ref>} : <ref:Protocol>Equatable</ref></decl>
// CHECK17-NEXT: }</synthesized>