@@ -21953,8 +21953,12 @@ func (c *Checker) getUnionOrIntersectionProperty(t *Type, name string, skipObjec
2195321953// unionOrIntersectionPropertySources describes the constituent properties from
2195421954// which a union or intersection property would be synthesized.
2195521955type unionOrIntersectionPropertySources struct {
21956- singleProp *ast.Symbol
21957- propSet collections.OrderedSet[*ast.Symbol]
21956+ singleProp *ast.Symbol
21957+ // props holds distinct constituent properties in first-seen order, or is
21958+ // empty when every constituent shares singleProp. propsByKey indexes it
21959+ // only once it is large enough for hashing to beat a linear scan.
21960+ props []*ast.Symbol
21961+ propsByKey map[*ast.Symbol]struct{}
2195821962 indexTypes []*Type
2195921963 propFlags ast.SymbolFlags
2196021964 optionalFlag ast.SymbolFlags
@@ -21966,7 +21970,30 @@ type unionOrIntersectionPropertySources struct {
2196621970// isSynthetic reports whether the sources require a new synthetic symbol rather
2196721971// than reusing (or cloning) singleProp.
2196821972func (s *unionOrIntersectionPropertySources) isSynthetic() bool {
21969- return s.propSet.Size() != 0 || s.checkFlags&ast.CheckFlagsReadPartial != 0 || len(s.indexTypes) != 0
21973+ return len(s.props) != 0 || s.checkFlags&ast.CheckFlagsReadPartial != 0 || len(s.indexTypes) != 0
21974+ }
21975+
21976+ // addProp adds prop to props if it is not already present, preserving
21977+ // first-insertion order.
21978+ func (s *unionOrIntersectionPropertySources) addProp(prop *ast.Symbol) {
21979+ if s.propsByKey == nil {
21980+ if slices.Contains(s.props, prop) {
21981+ return
21982+ }
21983+ s.props = append(s.props, prop)
21984+ if len(s.props) > orderedSetMapThreshold {
21985+ s.propsByKey = make(map[*ast.Symbol]struct{}, len(s.props))
21986+ for _, p := range s.props {
21987+ s.propsByKey[p] = struct{}{}
21988+ }
21989+ }
21990+ return
21991+ }
21992+ if _, ok := s.propsByKey[prop]; ok {
21993+ return
21994+ }
21995+ s.props = append(s.props, prop)
21996+ s.propsByKey[prop] = struct{}{}
2197021997}
2197121998
2197221999func (c *Checker) getUnionOrIntersectionPropertySources(containingType *Type, name string, skipObjectFunctionPropertyAugment bool, sources *unionOrIntersectionPropertySources) bool {
@@ -21976,7 +22003,6 @@ func (c *Checker) getUnionOrIntersectionPropertySources(containingType *Type, na
2197622003 var checkFlags ast.CheckFlags
2197722004 var optionalFlag ast.SymbolFlags
2197822005 var singleProp *ast.Symbol
21979- propSet := &sources.propSet
2198022006 var indexTypes []*Type
2198122007 if !isUnion {
2198222008 checkFlags = ast.CheckFlagsReadonly
@@ -22013,10 +22039,10 @@ func (c *Checker) getUnionOrIntersectionPropertySources(containingType *Type, na
2201322039 // back and not `Array<string>.length` when we're looking at a `.length` access on a `string[] | number[]`
2201422040 mergedInstantiations = singleProp.Parent() != nil && len(c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.Parent())) != 0
2201522041 } else {
22016- if propSet.Size( ) == 0 {
22017- propSet.Add (singleProp)
22042+ if len(sources.props ) == 0 {
22043+ sources.addProp (singleProp)
2201822044 }
22019- propSet.Add (prop)
22045+ sources.addProp (prop)
2202022046 }
2202122047 // classes created by mixins are represented as intersections
2202222048 // and overriding a property in a derived class redefines it completely at runtime
@@ -22082,9 +22108,9 @@ func (c *Checker) getUnionOrIntersectionPropertySources(containingType *Type, na
2208222108 return false
2208322109 }
2208422110 if isUnion &&
22085- (propSet.Size( ) != 0 || checkFlags&ast.CheckFlagsPartial != 0) &&
22111+ (len(sources.props ) != 0 || checkFlags&ast.CheckFlagsPartial != 0) &&
2208622112 checkFlags&(ast.CheckFlagsContainsPrivate|ast.CheckFlagsContainsProtected|ast.CheckFlagsContainsWritePrivate|ast.CheckFlagsContainsWriteProtected) != 0 &&
22087- !(propSet.Size( ) != 0 && c.hasCommonDeclaration(propSet )) {
22113+ !(len(sources.props ) != 0 && c.hasCommonDeclaration(sources.props )) {
2208822114 // A property in a union has a private or protected declaration in one constituent, but is missing
2208922115 // or has a different declaration in another constituent. If the private or protected declaration is
2209022116 // for reading, we don't create a property.
@@ -22115,7 +22141,6 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s
2211522141 return nil
2211622142 }
2211722143 singleProp := sources.singleProp
22118- propSet := &sources.propSet
2211922144 indexTypes := sources.indexTypes
2212022145 propFlags := sources.propFlags
2212122146 optionalFlag := sources.optionalFlag
@@ -22146,8 +22171,8 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s
2214622171 links.setWriteType(c, c.getWriteTypeOfSymbol(singleProp))
2214722172 return clone
2214822173 }
22149- if propSet.Size( ) == 0 {
22150- propSet.Add( singleProp)
22174+ if len(sources.props ) == 0 {
22175+ sources.props = []*ast.Symbol{ singleProp}
2215122176 }
2215222177 var declarations []*ast.Node
2215322178 var firstType *Type
@@ -22156,7 +22181,7 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s
2215622181 var writeTypes []*Type
2215722182 var firstValueDeclaration *ast.Node
2215822183 var hasNonUniformValueDeclaration bool
22159- for prop := range propSet.Values() {
22184+ for _, prop := range sources.props {
2216022185 if firstValueDeclaration == nil {
2216122186 firstValueDeclaration = prop.ValueDeclaration()
2216222187 } else if prop.ValueDeclaration() != nil && prop.ValueDeclaration() != firstValueDeclaration {
@@ -22240,9 +22265,9 @@ func isPrototypeProperty(symbol *ast.Symbol) bool {
2224022265 return symbol.Flags()&ast.SymbolFlagsMethod != 0 || symbol.CheckFlags()&ast.CheckFlagsSyntheticMethod != 0
2224122266}
2224222267
22243- func (c *Checker) hasCommonDeclaration(symbols *collections.OrderedSet[ *ast.Symbol] ) bool {
22268+ func (c *Checker) hasCommonDeclaration(symbols [] *ast.Symbol) bool {
2224422269 var commonDeclarations collections.Set[*ast.Node]
22245- for symbol := range symbols.Values() {
22270+ for _, symbol := range symbols {
2224622271 if len(symbol.Declarations()) == 0 {
2224722272 return false
2224822273 }
@@ -22459,15 +22484,15 @@ func (c *Checker) intersectionPropertyReducesToNever(t *Type, name string) bool
2245922484 prop := c.getUnionOrIntersectionProperty(t, name, true /*skipObjectFunctionPropertyAugment*/)
2246022485 return prop != nil && c.isNeverReducedProperty(prop)
2246122486 }
22462- if sources.propSet.Size( ) == 0 {
22463- sources.propSet.Add( sources.singleProp)
22487+ if len( sources.props ) == 0 {
22488+ sources.props = []*ast.Symbol{ sources.singleProp}
2246422489 }
2246522490 checkFlags := sources.checkFlags
2246622491 var firstType *Type
2246722492 var firstValueDeclaration *ast.Node
2246822493 hasNonUniformValueDeclaration := false
22469- propTypes := make([]*Type, 0, sources.propSet.Size( )+len(sources.indexTypes))
22470- for prop := range sources.propSet.Values() {
22494+ propTypes := make([]*Type, 0, len( sources.props )+len(sources.indexTypes))
22495+ for _, prop := range sources.props {
2247122496 if firstValueDeclaration == nil {
2247222497 firstValueDeclaration = prop.ValueDeclaration()
2247322498 } else if prop.ValueDeclaration() != nil && prop.ValueDeclaration() != firstValueDeclaration {
0 commit comments