Skip to content

Commit 06d1d50

Browse files
committed
[SymbolGraph] Ignore some Self requirements
To ease the burden on the client, ignore some generic requirements involving Self. For example, `Self: P` where we already know that `Self` conforms to `P`. An example case: ``` public struct S: Equatable { public static func ==(lhs: S, rhs: S) -> Bool { ... } } ``` `!=` is defined in terms of `Self` and the default implementation has a `Self: Equatable`. For the purposes of documentation, it's not necessary to specify that again on the page of documentation for `!=`. rdar://60963924
1 parent deb58e0 commit 06d1d50

File tree

9 files changed

+221
-42
lines changed

9 files changed

+221
-42
lines changed

lib/SymbolGraphGen/Edge.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ using namespace symbolgraphgen;
2121
void Edge::serialize(llvm::json::OStream &OS) const {
2222
OS.object([&](){
2323
OS.attribute("kind", Kind.Name);
24-
if (Kind == RelationshipKind::DefaultImplementationOf() && Source.getSynthesizedBaseTypeDecl()) {
25-
abort();
26-
}
2724
SmallString<256> SourceUSR, TargetUSR;
2825

2926
Source.getUSR(SourceUSR);
@@ -44,13 +41,22 @@ void Edge::serialize(llvm::json::OStream &OS) const {
4441
OS.attribute("targetFallback", Scratch.str());
4542
}
4643

47-
if (ConformanceExtension &&
48-
!ConformanceExtension->getGenericRequirements().empty()) {
49-
OS.attributeArray("swiftConstraints", [&](){
50-
for (const auto &Req : ConformanceExtension->getGenericRequirements()) {
51-
::serialize(Req, OS);
44+
if (ConformanceExtension) {
45+
if (const auto *Generics = ConformanceExtension->getAsGenericContext()) {
46+
SmallVector<Requirement, 4> FilteredRequirements;
47+
filterGenericRequirements(Generics->getGenericRequirements(),
48+
ConformanceExtension->getExtendedNominal()
49+
->getDeclContext()->getSelfNominalTypeDecl(),
50+
FilteredRequirements);
51+
if (!FilteredRequirements.empty()) {
52+
OS.attributeArray("swiftConstraints", [&](){
53+
for (const auto &Req :
54+
ConformanceExtension->getGenericRequirements()) {
55+
::serialize(Req, OS);
56+
}
57+
});
5258
}
53-
});
59+
}
5460
}
5561
});
5662
}

lib/SymbolGraphGen/JSON.cpp

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,21 @@ void swift::symbolgraphgen::serialize(const ExtensionDecl *Extension,
6666
OS.attribute("extendedModule", ExtendedModule->getNameStr());
6767
}
6868
}
69-
auto Generics = Extension->getGenericSignature();
70-
if (Generics && !Generics->getRequirements().empty()) {
71-
OS.attributeArray("constraints", [&](){
72-
for (const auto &Requirement : Generics->getRequirements()) {
73-
serialize(Requirement, OS);
74-
}
75-
}); // end constraints:
69+
if (const auto Generics = Extension->getAsGenericContext()) {
70+
SmallVector<Requirement, 4> FilteredRequirements;
71+
72+
filterGenericRequirements(Generics->getGenericRequirements(),
73+
Extension->getExtendedNominal()
74+
->getDeclContext()->getSelfNominalTypeDecl(),
75+
FilteredRequirements);
76+
77+
if (!FilteredRequirements.empty()) {
78+
OS.attributeArray("constraints", [&](){
79+
for (const auto &Requirement : FilteredRequirements) {
80+
serialize(Requirement, OS);
81+
}
82+
}); // end constraints:
83+
}
7684
}
7785
}); // end swiftExtension:
7886
}
@@ -81,16 +89,16 @@ void swift::symbolgraphgen::serialize(const Requirement &Req,
8189
llvm::json::OStream &OS) {
8290
StringRef Kind;
8391
switch (Req.getKind()) {
84-
case swift::RequirementKind::Conformance:
92+
case RequirementKind::Conformance:
8593
Kind = "conformance";
8694
break;
87-
case swift::RequirementKind::Superclass:
95+
case RequirementKind::Superclass:
8896
Kind = "superclass";
8997
break;
90-
case swift::RequirementKind::SameType:
98+
case RequirementKind::SameType:
9199
Kind = "sameType";
92100
break;
93-
case swift::RequirementKind::Layout:
101+
case RequirementKind::Layout:
94102
return;
95103
}
96104

@@ -99,5 +107,42 @@ void swift::symbolgraphgen::serialize(const Requirement &Req,
99107
OS.attribute("lhs", Req.getFirstType()->getString());
100108
OS.attribute("rhs", Req.getSecondType()->getString());
101109
});
110+
}
102111

112+
void swift::symbolgraphgen::serialize(const swift::GenericTypeParamType *Param,
113+
llvm::json::OStream &OS) {
114+
OS.object([&](){
115+
OS.attribute("name", Param->getName().str());
116+
OS.attribute("index", Param->getIndex());
117+
OS.attribute("depth", Param->getDepth());
118+
});
119+
}
120+
121+
void swift::symbolgraphgen::filterGenericRequirements(
122+
ArrayRef<Requirement> Requirements,
123+
const NominalTypeDecl *Self,
124+
SmallVectorImpl<Requirement> &FilteredRequirements) {
125+
for (const auto &Req : Requirements) {
126+
if (Req.getKind() == RequirementKind::Layout) {
127+
continue;
128+
}
129+
/*
130+
Don't serialize constraints that aren't applicable for display.
131+
132+
For example:
133+
134+
extension Equatable {
135+
func foo(_ thing: Self) {}
136+
}
137+
138+
`foo` includes a constraint `Self: Equatable` for the compiler's purposes,
139+
but that's redundant for the purposes of documentation.
140+
This is extending Equatable, after all!
141+
*/
142+
if (Req.getFirstType()->getString() == "Self" &&
143+
Req.getSecondType()->getAnyNominal() == Self) {
144+
continue;
145+
}
146+
FilteredRequirements.push_back(Req);
147+
}
103148
}

lib/SymbolGraphGen/JSON.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/Support/JSON.h"
2020
#include "llvm/Support/VersionTuple.h"
2121
#include "swift/AST/GenericSignature.h"
22+
#include "swift/AST/Type.h"
2223

2324
namespace swift {
2425
namespace symbolgraphgen {
@@ -40,7 +41,15 @@ void serialize(const llvm::VersionTuple &VT, llvm::json::OStream &OS);
4041
void serialize(const llvm::Triple &T, llvm::json::OStream &OS);
4142
void serialize(const ExtensionDecl *Extension, llvm::json::OStream &OS);
4243
void serialize(const Requirement &Req, llvm::json::OStream &OS);
44+
void serialize(const swift::GenericTypeParamType *Param,
45+
llvm::json::OStream &OS);
4346

47+
48+
/// Filter generic requirements that aren't relevant for documentation.
49+
void
50+
filterGenericRequirements(ArrayRef<Requirement> Requirements,
51+
const NominalTypeDecl *Self,
52+
SmallVectorImpl<Requirement> &FilteredRequirements);
4453
} // end namespace symbolgraphgen
4554
} // end namespace swift
4655

lib/SymbolGraphGen/Symbol.cpp

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -236,41 +236,50 @@ void Symbol::serializeFunctionSignature(llvm::json::OStream &OS) const {
236236
}
237237
}
238238

239-
void Symbol::serializeGenericParam(const swift::GenericTypeParamType &Param,
240-
llvm::json::OStream &OS) const {
241-
OS.object([&](){
242-
OS.attribute("name", Param.getName().str());
243-
OS.attribute("index", Param.getIndex());
244-
OS.attribute("depth", Param.getDepth());
245-
});
246-
}
247-
248239
void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const {
249240
if (const auto *GC = VD->getAsGenericContext()) {
250-
if (const auto Generics = GC->getGenericSignature()) {
241+
if (const auto Generics = GC->getGenericSignature()) {
242+
243+
SmallVector<const GenericTypeParamType *, 4> FilteredParams;
244+
SmallVector<Requirement, 4> FilteredRequirements;
245+
for (const auto Param : Generics->getGenericParams()) {
246+
if (const auto *D = Param->getDecl()) {
247+
if (D->isImplicit()) {
248+
continue;
249+
}
250+
FilteredParams.push_back(Param);
251+
}
252+
}
253+
254+
const auto *Self = dyn_cast<NominalTypeDecl>(VD);
255+
if (!Self) {
256+
Self = VD->getDeclContext()->getSelfNominalTypeDecl();
257+
}
258+
259+
filterGenericRequirements(Generics->getRequirements(),
260+
Self,
261+
FilteredRequirements);
262+
263+
if (FilteredParams.empty() && FilteredRequirements.empty()) {
264+
return;
265+
}
251266

252267
OS.attributeObject("swiftGenerics", [&](){
253-
if (!Generics->getGenericParams().empty()) {
268+
if (!FilteredParams.empty()) {
254269
OS.attributeArray("parameters", [&](){
255-
for (const auto Param : Generics->getGenericParams()) {
256-
if (const auto *D = Param->getDecl()) {
257-
if (D->isImplicit()) {
258-
continue;
259-
}
260-
}
261-
serializeGenericParam(*Param, OS);
270+
for (const auto *Param : FilteredParams) {
271+
::serialize(Param, OS);
262272
}
263273
}); // end parameters:
264274
}
265275

266-
if (!Generics->getRequirements().empty()) {
276+
if (!FilteredRequirements.empty()) {
267277
OS.attributeArray("constraints", [&](){
268-
for (const auto &Requirement : Generics->getRequirements()) {
269-
::serialize(Requirement, OS);
278+
for (const auto &Req : FilteredRequirements) {
279+
::serialize(Req, OS);
270280
}
271281
}); // end constraints:
272282
}
273-
274283
}); // end swiftGenerics:
275284
}
276285
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name Arguments -emit-module-path %t/Arguments.swiftmodule
3+
// RUN: %target-swift-symbolgraph-extract -module-name Arguments -I %t -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/Arguments.symbols.json
5+
6+
public struct MyStruct<T> {
7+
public var x: T
8+
public init(x: T) {
9+
self.x = x
10+
}
11+
}
12+
13+
// CHECK: swiftGenerics
14+
// CHECK-NEXT: "parameters": [
15+
// CHECK-NEXT: {
16+
// CHECK-NEXT: "name": "T"
17+
// CHECK-NEXT: "index": 0
18+
// CHECK-NEXT: "depth": 0
19+
// CHECK-NEXT: }
20+
// CHECK-NEXT: ]
21+
// CHECK-NOT: constraints
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name ConstraintsOnLocalContext -emit-module-path %t/ConstraintsOnLocalContext.swiftmodule
3+
// RUN: %target-swift-symbolgraph-extract -module-name ConstraintsOnLocalContext -I %t -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/ConstraintsOnLocalContext.symbols.json
5+
6+
public func foo<T: Sequence>(x: T) {}
7+
8+
// CHECK: swiftGenerics
9+
// CHECK-NEXT: "parameters": [
10+
// {
11+
// CHECK: "name": "T"
12+
// CHECK-NEXT: "index": 0
13+
// CHECK-NEXT: "depth": 0
14+
// CHECK-NEXT: }
15+
// CHECK-NEXT: ]
16+
// CHECK-NEXT: "constraints": [
17+
// {
18+
// CHECK: "kind": "conformance"
19+
// CHECK-NEXT: "lhs": "T"
20+
// CHECK-NEXT: "rhs": "Sequence"
21+
// CHECK-NEXT: }
22+
// CHECK-NEXT: ]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name ConstraintsOnOuterContext -emit-module-path %t/ConstraintsOnOuterContext.swiftmodule
3+
// RUN: %target-swift-symbolgraph-extract -module-name ConstraintsOnOuterContext -I %t -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/ConstraintsOnOuterContext.symbols.json
5+
6+
public struct MyStruct<S: Sequence> {
7+
public var x: S
8+
public init(x: S) {
9+
self.x = x
10+
}
11+
public func foo() where S.Element == Int {}
12+
}
13+
14+
// CHECK-LABEL: "precise": "s:25ConstraintsOnOuterContext8MyStructV3fooyySi7ElementRtzrlF"
15+
// CHECK: swiftGenerics
16+
// CHECK: "constraints": [
17+
// {
18+
// CHECK: "kind": "conformance"
19+
// CHECK-NEXT: "lhs": "S"
20+
// CHECK-NEXT: "rhs": "Sequence"
21+
// },
22+
// {
23+
// CHECK: "kind": "sameType"
24+
// CHECK-NEXT: "lhs": "S.Element"
25+
// CHECK-NEXT: "rhs": "Int"
26+
// CHECK-NEXT: }
27+
// CHECK-NEXT: ]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name Self -emit-module-path %t/Self.swiftmodule
3+
// RUN: %target-swift-symbolgraph-extract -module-name Self -I %t -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/Self.symbols.json
5+
6+
public protocol P {}
7+
extension P {
8+
static func foo(_ thing: Self) {}
9+
}
10+
11+
public struct MyStruct: Equatable {
12+
public static func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
13+
return true
14+
}
15+
}
16+
17+
// We don't want Self: Equatable to show up here for !=
18+
// CHECK-NOT: swiftGenerics
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name WhereClause -emit-module-path %t/WhereClause.swiftmodule
3+
// RUN: %target-swift-symbolgraph-extract -module-name WhereClause -I %t -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/WhereClause.symbols.json
5+
6+
public func foo<T>(x: T) where T: Sequence {}
7+
8+
// CHECK: swiftGenerics
9+
// CHECK-NEXT: "parameters": [
10+
// {
11+
// CHECK: "name": "T"
12+
// CHECK-NEXT: "index": 0
13+
// CHECK-NEXT: "depth": 0
14+
// CHECK-NEXT: }
15+
// CHECK-NEXT: ]
16+
// CHECK-NEXT: "constraints": [
17+
// {
18+
// CHECK: "kind": "conformance"
19+
// CHECK-NEXT: "lhs": "T"
20+
// CHECK-NEXT: "rhs": "Sequence"
21+
// CHECK-NEXT: }
22+
// CHECK-NEXT: ]

0 commit comments

Comments
 (0)