Skip to content

Commit 7363c09

Browse files
authored
Add test which ensures type sorting is consistent (#444)
1 parent a11e468 commit 7363c09

File tree

4 files changed

+53
-14
lines changed

4 files changed

+53
-14
lines changed

internal/checker/checker.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package checker
22

33
import (
44
"fmt"
5+
"iter"
56
"maps"
67
"math"
78
"slices"
@@ -23721,6 +23722,10 @@ func (c *Checker) getUnionTypeFromSortedList(types []*Type, precomputedObjectFla
2372123722
return t
2372223723
}
2372323724

23725+
func (c *Checker) UnionTypes() iter.Seq[*Type] {
23726+
return maps.Values(c.unionTypes)
23727+
}
23728+
2372423729
func (c *Checker) addTypesToUnion(typeSet []*Type, includes TypeFlags, types []*Type) ([]*Type, TypeFlags) {
2372523730
var lastType *Type
2372623731
for _, t := range types {
@@ -23762,7 +23767,7 @@ func (c *Checker) addTypeToUnion(typeSet []*Type, includes TypeFlags, t *Type) (
2376223767
includes |= TypeFlagsIncludesNonWideningType
2376323768
}
2376423769
} else {
23765-
if index, ok := slices.BinarySearchFunc(typeSet, t, compareTypes); !ok {
23770+
if index, ok := slices.BinarySearchFunc(typeSet, t, CompareTypes); !ok {
2376623771
typeSet = slices.Insert(typeSet, index, t)
2376723772
}
2376823773
}
@@ -24528,12 +24533,12 @@ func (c *Checker) removeType(t *Type, targetType *Type) *Type {
2452824533
}
2452924534

2453024535
func containsType(types []*Type, t *Type) bool {
24531-
_, ok := slices.BinarySearchFunc(types, t, compareTypes)
24536+
_, ok := slices.BinarySearchFunc(types, t, CompareTypes)
2453224537
return ok
2453324538
}
2453424539

2453524540
func insertType(types []*Type, t *Type) ([]*Type, bool) {
24536-
if i, ok := slices.BinarySearchFunc(types, t, compareTypes); !ok {
24541+
if i, ok := slices.BinarySearchFunc(types, t, CompareTypes); !ok {
2453724542
return slices.Insert(types, i, t), true
2453824543
}
2453924544
return types, false

internal/checker/utilities.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ func (c *Checker) compareNodes(n1, n2 *ast.Node) int {
665665
return n1.Pos() - n2.Pos()
666666
}
667667

668-
func compareTypes(t1, t2 *Type) int {
668+
func CompareTypes(t1, t2 *Type) int {
669669
if t1 == t2 {
670670
return 0
671671
}
@@ -750,7 +750,7 @@ func compareTypes(t1, t2 *Type) int {
750750
} else if o2 == nil {
751751
return -1
752752
} else {
753-
if c := compareTypes(o1, o2); c != 0 {
753+
if c := CompareTypes(o1, o2); c != 0 {
754754
return c
755755
}
756756
}
@@ -788,17 +788,17 @@ func compareTypes(t1, t2 *Type) int {
788788
return c
789789
}
790790
case t1.flags&TypeFlagsIndex != 0:
791-
if c := compareTypes(t1.AsIndexType().target, t2.AsIndexType().target); c != 0 {
791+
if c := CompareTypes(t1.AsIndexType().target, t2.AsIndexType().target); c != 0 {
792792
return c
793793
}
794794
if c := int(t1.AsIndexType().flags) - int(t2.AsIndexType().flags); c != 0 {
795795
return c
796796
}
797797
case t1.flags&TypeFlagsIndexedAccess != 0:
798-
if c := compareTypes(t1.AsIndexedAccessType().objectType, t2.AsIndexedAccessType().objectType); c != 0 {
798+
if c := CompareTypes(t1.AsIndexedAccessType().objectType, t2.AsIndexedAccessType().objectType); c != 0 {
799799
return c
800800
}
801-
if c := compareTypes(t1.AsIndexedAccessType().indexType, t2.AsIndexedAccessType().indexType); c != 0 {
801+
if c := CompareTypes(t1.AsIndexedAccessType().indexType, t2.AsIndexedAccessType().indexType); c != 0 {
802802
return c
803803
}
804804
case t1.flags&TypeFlagsConditional != 0:
@@ -809,10 +809,10 @@ func compareTypes(t1, t2 *Type) int {
809809
return c
810810
}
811811
case t1.flags&TypeFlagsSubstitution != 0:
812-
if c := compareTypes(t1.AsSubstitutionType().baseType, t2.AsSubstitutionType().baseType); c != 0 {
812+
if c := CompareTypes(t1.AsSubstitutionType().baseType, t2.AsSubstitutionType().baseType); c != 0 {
813813
return c
814814
}
815-
if c := compareTypes(t1.AsSubstitutionType().constraint, t2.AsSubstitutionType().constraint); c != 0 {
815+
if c := CompareTypes(t1.AsSubstitutionType().constraint, t2.AsSubstitutionType().constraint); c != 0 {
816816
return c
817817
}
818818
case t1.flags&TypeFlagsTemplateLiteral != 0:
@@ -823,7 +823,7 @@ func compareTypes(t1, t2 *Type) int {
823823
return c
824824
}
825825
case t1.flags&TypeFlagsStringMapping != 0:
826-
if c := compareTypes(t1.AsStringMappingType().target, t2.AsStringMappingType().target); c != 0 {
826+
if c := CompareTypes(t1.AsStringMappingType().target, t2.AsStringMappingType().target); c != 0 {
827827
return c
828828
}
829829
}
@@ -915,7 +915,7 @@ func compareTypeLists(s1, s2 []*Type) int {
915915
return len(s1) - len(s2)
916916
}
917917
for i, t1 := range s1 {
918-
if c := compareTypes(t1, s2[i]); c != 0 {
918+
if c := CompareTypes(t1, s2[i]); c != 0 {
919919
return c
920920
}
921921
}
@@ -941,10 +941,10 @@ func compareTypeMappers(m1, m2 *TypeMapper) int {
941941
case TypeMapperKindSimple:
942942
m1 := m1.data.(*SimpleTypeMapper)
943943
m2 := m2.data.(*SimpleTypeMapper)
944-
if c := compareTypes(m1.source, m2.source); c != 0 {
944+
if c := CompareTypes(m1.source, m2.source); c != 0 {
945945
return c
946946
}
947-
return compareTypes(m1.target, m2.target)
947+
return CompareTypes(m1.target, m2.target)
948948
case TypeMapperKindArray:
949949
m1 := m1.data.(*ArrayTypeMapper)
950950
m2 := m2.data.(*ArrayTypeMapper)

internal/compiler/program.go

+5
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,11 @@ func (p *Program) GetTypeChecker() *checker.Checker {
233233
return p.checkers[0]
234234
}
235235

236+
func (p *Program) GetTypeCheckers() []*checker.Checker {
237+
p.createCheckers()
238+
return p.checkers
239+
}
240+
236241
// Return a checker for the given file. We may have multiple checkers in concurrent scenarios and this
237242
// method returns the checker that was tasked with checking the file. Note that it isn't possible to mix
238243
// types obtained from different checkers, so only non-type data (such as diagnostics or string

internal/testrunner/compiler_runner.go

+29
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package runner
22

33
import (
44
"fmt"
5+
"math/rand/v2"
56
"os"
67
"path/filepath"
78
"regexp"
89
"slices"
910
"strings"
1011
"testing"
1112

13+
"github.com/microsoft/typescript-go/internal/checker"
1214
"github.com/microsoft/typescript-go/internal/core"
1315
"github.com/microsoft/typescript-go/internal/repo"
1416
"github.com/microsoft/typescript-go/internal/testutil"
@@ -18,6 +20,7 @@ import (
1820
"github.com/microsoft/typescript-go/internal/tsoptions"
1921
"github.com/microsoft/typescript-go/internal/tspath"
2022
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
23+
"gotest.tools/v3/assert"
2124
)
2225

2326
var (
@@ -183,6 +186,8 @@ func (r *CompilerBaselineRunner) runSingleConfigTest(t *testing.T, testName stri
183186
compilerTest.verifyJavaScriptOutput(t, r.testSuitName, r.isSubmodule)
184187
compilerTest.verifyTypesAndSymbols(t, r.testSuitName, r.isSubmodule)
185188
// !!! Verify all baselines
189+
190+
compilerTest.verifyUnionOrdering(t)
186191
}
187192

188193
type compilerFileBasedTest struct {
@@ -414,3 +419,27 @@ func createHarnessTestFile(unit *testUnit, currentDirectory string) *harnessutil
414419
Content: unit.content,
415420
}
416421
}
422+
423+
func (c *compilerTest) verifyUnionOrdering(t *testing.T) {
424+
t.Run("union ordering", func(t *testing.T) {
425+
for _, c := range c.result.Program.GetTypeCheckers() {
426+
for union := range c.UnionTypes() {
427+
types := union.Types()
428+
429+
reversed := slices.Clone(types)
430+
slices.Reverse(reversed)
431+
slices.SortFunc(reversed, checker.CompareTypes)
432+
assert.Assert(t, slices.Equal(reversed, types), "compareTypes does not sort union types consistently")
433+
434+
shuffled := slices.Clone(types)
435+
rng := rand.New(rand.NewPCG(1234, 5678))
436+
437+
for range 10 {
438+
rng.Shuffle(len(shuffled), func(i, j int) { shuffled[i], shuffled[j] = shuffled[j], shuffled[i] })
439+
slices.SortFunc(shuffled, checker.CompareTypes)
440+
assert.Assert(t, slices.Equal(shuffled, types), "compareTypes does not sort union types consistently")
441+
}
442+
}
443+
}
444+
})
445+
}

0 commit comments

Comments
 (0)