59 lines
2.2 KiB
Markdown
59 lines
2.2 KiB
Markdown
# 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).
|