i was curious as to why some generated DocC/Unidoc symbol pages are missing certain crucial generic constraints gating the symbols.
to my surprise, i found that lib/SymbolGraphGen ignores associatedtype constraints entirely when it computes the generic context for a declaration. in the following example, only the Self constraint is detected by SymbolGraphGen; the RawValue constraint is ignored entirely.
public
protocol Protocol
{
}
extension Protocol where Self:RawRepresentable, RawValue:Protocol
{
public
func f() { }
}
{
...
"pathComponents": [
"Protocol",
"f()"
],
"swiftGenerics": {
"constraints": [
{
"kind": "conformance",
"lhs": "Self",
"rhs": "RawRepresentable",
"rhsPrecise": "s:SY"
}
]
},
"swiftExtension": {
"extendedModule": "ConditionalDefaultImplementations",
"typeKind": "swift.protocol",
"constraints": [
{
"kind": "conformance",
"lhs": "Self",
"rhs": "RawRepresentable",
"rhsPrecise": "s:SY"
}
]
},
...
},
is there a reason why SymbolGraphGen does not consider associated type constraints when it computes generics?
While I don't follow the logic in the code, I believe they're getting filtered out here: https://github.com/apple/swift/blob/main/lib/SymbolGraphGen/JSON.cpp#L219
I think this part is trying to filter out requirements of a member that are already satisfied by the extension itself:
// extension /* protocol */ Q {
// func foo() {}
// }
// ignore Self : Q, obvious
if (Req.getSecondType()->getAnyNominal() == Self) {
continue;
}
This can be achieved with requirementsNotSatisfiedBy() instead. It will also handle cases like
extension Q where Self.A : P {
func foo() // we want to filter out `Self.A: P` here presumably too and not just `Self: Q`
}
The immediate problem might be that containsParams() finds an archetype whose interface type is a DependentMemberType (Self.RawValue) and not a GenericTypeParameterType, so containsParams() returns false.
This part is also worth revisiting:
if (Req.getKind() == RequirementKind::Layout) {
continue;
}
Self.A: AnyObject is a Layout requirement. Those should not be simply dropped, instead they can also be transformed in various ways, but they only have a getFirstType() and not a getSecondType(), so we just need to handle that case.
@taylorswift I've seen other posts from you where you've been playing with SymbolGraph, if you wanted to try to learn about this code and refactor some of the above a little, I'd be happy to review PRs and offer guidance.
2 Likes