java-topology/defects/swift/patch/swift-0002-requirement-machine-set.md

59 lines
2.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# swift-0001: isInMinimizationDomain — O(P) linear scan in O(R) rule loop
## Severity: HIGH
## Location
- `lib/AST/RequirementMachine/RewriteSystem.cpp:484`
- Called from loops in:
- `lib/AST/RequirementMachine/HomotopyReduction.cpp:611,659,753`
- `lib/AST/RequirementMachine/MinimalConformances.cpp:326`
- `lib/AST/RequirementMachine/Diagnostics.cpp:349`
- `lib/AST/RequirementMachine/PropertyUnification.cpp:133`
## Description
`RewriteSystem::isInMinimizationDomain()` performs a linear `std::find` scan over
`Protos` (an `ArrayRef<const ProtocolDecl *>`) on every call. This function is invoked
inside loops over all rewrite `Rules` (size scales with protocol graph complexity).
**Complexity:** O(R × P) where R = rule count, P = protocol count in connected component.
For a deeply hierarchical protocol graph with N protocols, both R and P are O(N),
yielding O(N²) total cost during requirement signature minimization.
## Root Cause
```cpp
// RewriteSystem.cpp:478
bool RewriteSystem::isInMinimizationDomain(const ProtocolDecl *proto) const {
// ...
if (std::find(Protos.begin(), Protos.end(), proto) != Protos.end())
return true;
return false;
}
```
`Protos` is `ArrayRef<const ProtocolDecl *>` — a plain pointer array. `std::find` is O(P).
Called inside every rule-scanning loop; no caching or set-based lookup.
## Fix
Replace `ArrayRef<const ProtocolDecl *> Protos` with `llvm::DenseSet<const ProtocolDecl *> ProtoSet`
populated once at construction, or cache a `llvm::SmallPtrSet` alongside the ArrayRef.
Then `isInMinimizationDomain` becomes an O(1) hash set lookup.
```cpp
// In RewriteSystem.h, add:
llvm::SmallPtrSet<const ProtocolDecl *, 8> ProtoSet;
// In RewriteSystem::init or wherever Protos is set:
ProtoSet.insert(Protos.begin(), Protos.end());
// In isInMinimizationDomain:
bool RewriteSystem::isInMinimizationDomain(const ProtocolDecl *proto) const {
if (proto == nullptr && Protos.empty())
return true;
return ProtoSet.count(proto) > 0;
}
```
## Impact
Protocol-heavy Swift code (many protocols with complex inheritance) hits O(N²) during
generic signature computation. Manifest as slow compilation on codebases with many protocols
or deep protocol hierarchies (e.g., Combine/SwiftUI framework chains).