Skip to content

Commit 97aedd3

Browse files
authored
Speed up union subset checks by scanning sorted constituents (#64964)
1 parent 615d415 commit 97aedd3

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

‎tsc/internal/checker/relater.go‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package checker
22

33
import (
4+
"math/bits"
45
"slices"
56
"strconv"
67
"strings"
@@ -2869,10 +2870,29 @@ func (c *Checker) isTypeSubsetOf(source *Type, target *Type) bool {
28692870

28702871
func (c *Checker) isTypeSubsetOfUnion(source *Type, target *Type) bool {
28712872
if source.flags&TypeFlagsUnion != 0 {
2872-
for _, t := range source.Types() {
2873-
if !containsType(target.Types(), t) {
2873+
sourceTypes, targetTypes := source.Types(), target.Types()
2874+
if len(sourceTypes) > len(targetTypes) {
2875+
return false
2876+
}
2877+
// Scan by identity unless a few source types are looked for in a large target. A CompareTypes call costs
2878+
// roughly 8 pointer comparisons, so there a binary search is cheaper than walking the target.
2879+
if len(sourceTypes)*bits.Len(uint(len(targetTypes)))*8 >= len(targetTypes) {
2880+
for _, t := range sourceTypes {
2881+
i := slices.Index(targetTypes, t)
2882+
if i < 0 {
2883+
return false
2884+
}
2885+
// Union types are sorted by CompareTypes, so the next source type can only appear after this one.
2886+
targetTypes = targetTypes[i+1:]
2887+
}
2888+
return true
2889+
}
2890+
for _, t := range sourceTypes {
2891+
i, found := slices.BinarySearchFunc(targetTypes, t, CompareTypes)
2892+
if !found {
28742893
return false
28752894
}
2895+
targetTypes = targetTypes[i+1:]
28762896
}
28772897
return true
28782898
}

0 commit comments

Comments
 (0)