@@ -21950,15 +21950,34 @@ func (c *Checker) getUnionOrIntersectionProperty(t *Type, name string, skipObjec
2195021950 return prop
2195121951}
2195221952
21953- func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol {
21953+ // unionOrIntersectionPropertySources describes the constituent properties from
21954+ // which a union or intersection property would be synthesized.
21955+ type unionOrIntersectionPropertySources struct {
21956+ singleProp *ast.Symbol
21957+ propSet collections.OrderedSet[*ast.Symbol]
21958+ indexTypes []*Type
21959+ propFlags ast.SymbolFlags
21960+ optionalFlag ast.SymbolFlags
21961+ checkFlags ast.CheckFlags
21962+ syntheticFlag ast.CheckFlags
21963+ mergedInstantiations bool
21964+ }
21965+
21966+ // isSynthetic reports whether the sources require a new synthetic symbol rather
21967+ // than reusing (or cloning) singleProp.
21968+ func (s *unionOrIntersectionPropertySources) isSynthetic() bool {
21969+ return s.propSet.Size() != 0 || s.checkFlags&ast.CheckFlagsReadPartial != 0 || len(s.indexTypes) != 0
21970+ }
21971+
21972+ func (c *Checker) getUnionOrIntersectionPropertySources(containingType *Type, name string, skipObjectFunctionPropertyAugment bool, sources *unionOrIntersectionPropertySources) bool {
2195421973 propFlags := ast.SymbolFlagsNone
21955- var singleProp *ast.Symbol
21956- var propSet collections.OrderedSet[*ast.Symbol]
21957- var indexTypes []*Type
2195821974 isUnion := containingType.flags&TypeFlagsUnion != 0
2195921975 // Flags we want to propagate to the result if they exist in all source symbols
2196021976 var checkFlags ast.CheckFlags
2196121977 var optionalFlag ast.SymbolFlags
21978+ var singleProp *ast.Symbol
21979+ propSet := &sources.propSet
21980+ var indexTypes []*Type
2196221981 if !isUnion {
2196321982 checkFlags = ast.CheckFlagsReadonly
2196421983 optionalFlag = ast.SymbolFlagsOptional
@@ -22060,17 +22079,17 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s
2206022079 }
2206122080 if singleProp == nil {
2206222081 // No property was found
22063- return nil
22082+ return false
2206422083 }
2206522084 if isUnion &&
2206622085 (propSet.Size() != 0 || checkFlags&ast.CheckFlagsPartial != 0) &&
2206722086 checkFlags&(ast.CheckFlagsContainsPrivate|ast.CheckFlagsContainsProtected|ast.CheckFlagsContainsWritePrivate|ast.CheckFlagsContainsWriteProtected) != 0 &&
22068- !(propSet.Size() != 0 && c.hasCommonDeclaration(& propSet)) {
22087+ !(propSet.Size() != 0 && c.hasCommonDeclaration(propSet)) {
2206922088 // A property in a union has a private or protected declaration in one constituent, but is missing
2207022089 // or has a different declaration in another constituent. If the private or protected declaration is
2207122090 // for reading, we don't create a property.
2207222091 if checkFlags&(ast.CheckFlagsContainsPrivate|ast.CheckFlagsContainsProtected) != 0 {
22073- return nil
22092+ return false
2207422093 }
2207522094 // Otherwise, if the private or protected declaration is for writing, reduce accessibility to that of
2207622095 // the most restricted constituent.
@@ -22080,8 +22099,31 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s
2208022099 checkFlags &^= ast.CheckFlagsContainsWritePublic
2208122100 }
2208222101 }
22083- if propSet.Size() == 0 && checkFlags&ast.CheckFlagsReadPartial == 0 && len(indexTypes) == 0 {
22084- if !mergedInstantiations {
22102+ sources.singleProp = singleProp
22103+ sources.indexTypes = indexTypes
22104+ sources.propFlags = propFlags
22105+ sources.optionalFlag = optionalFlag
22106+ sources.checkFlags = checkFlags
22107+ sources.syntheticFlag = syntheticFlag
22108+ sources.mergedInstantiations = mergedInstantiations
22109+ return true
22110+ }
22111+
22112+ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol {
22113+ var sources unionOrIntersectionPropertySources
22114+ if !c.getUnionOrIntersectionPropertySources(containingType, name, skipObjectFunctionPropertyAugment, &sources) {
22115+ return nil
22116+ }
22117+ singleProp := sources.singleProp
22118+ propSet := &sources.propSet
22119+ indexTypes := sources.indexTypes
22120+ propFlags := sources.propFlags
22121+ optionalFlag := sources.optionalFlag
22122+ checkFlags := sources.checkFlags
22123+ syntheticFlag := sources.syntheticFlag
22124+ isUnion := containingType.flags&TypeFlagsUnion != 0
22125+ if !sources.isSynthetic() {
22126+ if !sources.mergedInstantiations {
2208522127 return singleProp
2208622128 }
2208722129 // No symbol from a union/intersection should have a `.parent` set (since unions/intersections don't act as symbol parents)
@@ -22390,14 +22432,72 @@ func (c *Checker) somePropertyReducesToNever(t *Type) bool {
2239022432 // Go in the order the properties were found so the combined properties are created in the same order every time.
2239122433 for propName, count := range counts.Entries() {
2239222434 if count > 1 {
22393- if prop := c.getPropertyOfUnionOrIntersectionType (t, propName, true /*skipObjectFunctionPropertyAugment*/); prop != nil && c.isNeverReducedProperty(prop ) {
22435+ if c.intersectionPropertyReducesToNever (t, propName) {
2239422436 return true
2239522437 }
2239622438 }
2239722439 }
2239822440 return false
2239922441}
2240022442
22443+ // intersectionPropertyReducesToNever reports whether the combined property named
22444+ // name would satisfy isNeverReducedProperty, without creating and caching that
22445+ // property. Most such properties are never otherwise looked up, so creating
22446+ // them only to inspect their flags retains a large number of symbols.
22447+ func (c *Checker) intersectionPropertyReducesToNever(t *Type, name string) bool {
22448+ if prop := t.AsUnionOrIntersectionType().propertyCacheWithoutFunctionPropertyAugment[name]; prop != nil {
22449+ return c.isNeverReducedProperty(prop)
22450+ }
22451+ var sources unionOrIntersectionPropertySources
22452+ if !c.getUnionOrIntersectionPropertySources(t, name, true /*skipObjectFunctionPropertyAugment*/, &sources) {
22453+ return false
22454+ }
22455+ if !sources.isSynthetic() {
22456+ if !sources.mergedInstantiations {
22457+ return c.isNeverReducedProperty(sources.singleProp)
22458+ }
22459+ prop := c.getUnionOrIntersectionProperty(t, name, true /*skipObjectFunctionPropertyAugment*/)
22460+ return prop != nil && c.isNeverReducedProperty(prop)
22461+ }
22462+ if sources.propSet.Size() == 0 {
22463+ sources.propSet.Add(sources.singleProp)
22464+ }
22465+ checkFlags := sources.checkFlags
22466+ var firstType *Type
22467+ var firstValueDeclaration *ast.Node
22468+ hasNonUniformValueDeclaration := false
22469+ propTypes := make([]*Type, 0, sources.propSet.Size()+len(sources.indexTypes))
22470+ for prop := range sources.propSet.Values() {
22471+ if firstValueDeclaration == nil {
22472+ firstValueDeclaration = prop.ValueDeclaration()
22473+ } else if prop.ValueDeclaration() != nil && prop.ValueDeclaration() != firstValueDeclaration {
22474+ hasNonUniformValueDeclaration = true
22475+ }
22476+ propType := c.getTypeOfSymbol(prop)
22477+ if firstType == nil {
22478+ firstType = propType
22479+ }
22480+ if propType != firstType {
22481+ checkFlags |= ast.CheckFlagsHasNonUniformType
22482+ }
22483+ if isLiteralType(propType) || c.isPatternLiteralType(propType) {
22484+ checkFlags |= ast.CheckFlagsHasLiteralType
22485+ }
22486+ if propType.flags&TypeFlagsNever != 0 && propType != c.uniqueLiteralType {
22487+ checkFlags |= ast.CheckFlagsHasNeverType
22488+ }
22489+ propTypes = append(propTypes, propType)
22490+ }
22491+ propTypes = append(propTypes, sources.indexTypes...)
22492+ hasValueDeclaration := !hasNonUniformValueDeclaration && firstValueDeclaration != nil
22493+ if !hasValueDeclaration && checkFlags&ast.CheckFlagsContainsPrivate != 0 {
22494+ return true
22495+ }
22496+ return (sources.propFlags|sources.optionalFlag)&ast.SymbolFlagsOptional == 0 &&
22497+ checkFlags&(ast.CheckFlagsNonUniformAndLiteral|ast.CheckFlagsHasNeverType) == ast.CheckFlagsNonUniformAndLiteral &&
22498+ c.getIntersectionType(propTypes).flags&TypeFlagsNever != 0
22499+ }
22500+
2240122501func (c *Checker) getReducedUnionType(unionType *Type) *Type {
2240222502 reducedTypes := core.SameMap(unionType.Types(), c.getReducedType)
2240322503 if core.Same(reducedTypes, unionType.Types()) {
0 commit comments