Skip to content

Commit c501b1f

Browse files
committed
Remove ObjectFlagsMembersResolving
The flag marked members whose resolution was in progress, so that the fast path would not read members published before they were complete. That duplicates what the resolution stack already records: the resolution of the members is in Checker.resolving, or shadowed by a cycle yield. The flag also let a type carry a "resolved" bit for members that were not yet final, which is the install-then-replace pattern Anders Hejlsberg objected to in the review of "Allow accessing named declared members during a type's resolution". ObjectFlagsMembersResolved now means only that the outermost resolution of the members completed. Whether partial members are available to a computation re-entering the resolution is recorded on the resolution itself (membersPublished), and a re-entry finds it even when hidden by a cycle yield. Members are marked published before their properties are listed, since listing them may re-enter the resolution, which then sees the members as it did before. Types created with their members, rather than resolved, still set the flag directly through setStructuredTypeMembers; resolvers use setStructuredTypeData or publishStructuredTypeMembers.
1 parent 46cb662 commit c501b1f

7 files changed

Lines changed: 127 additions & 78 deletions

File tree

‎packages/typescript/enums/objectFlags.d.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export declare enum ObjectFlags {
2424
CouldContainTypeVariablesComputed = 1 << 19,
2525
CouldContainTypeVariables = 1 << 20,
2626
MembersResolved = 1 << 21,
27-
MembersResolving = 1 << 30,
2827
ClassOrInterface = Class | Interface,
2928
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,
3029
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType,

‎packages/typescript/enums/objectFlags.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export var ObjectFlags;
2424
ObjectFlags[ObjectFlags["CouldContainTypeVariablesComputed"] = 524288] = "CouldContainTypeVariablesComputed";
2525
ObjectFlags[ObjectFlags["CouldContainTypeVariables"] = 1048576] = "CouldContainTypeVariables";
2626
ObjectFlags[ObjectFlags["MembersResolved"] = 2097152] = "MembersResolved";
27-
ObjectFlags[ObjectFlags["MembersResolving"] = 1073741824] = "MembersResolving";
2827
ObjectFlags[ObjectFlags["ClassOrInterface"] = 3] = "ClassOrInterface";
2928
ObjectFlags[ObjectFlags["RequiresWidening"] = 196608] = "RequiresWidening";
3029
ObjectFlags[ObjectFlags["PropagatingFlags"] = 458752] = "PropagatingFlags";

‎tsc/internal/api/enum_values_generated.go‎

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tsc/internal/checker/checker.go‎

Lines changed: 100 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -20303,16 +20303,6 @@ func (c *Checker) yieldCycle(start int) bool {
2030320303
return true
2030420304
}
2030520305

20306-
// observeHiddenMembers fails the cycle yield in progress if the members of t
20307-
// are being resolved below it. Members are made available while they are
20308-
// resolved, so the yield would see whatever part of them the hidden
20309-
// resolution has published, rather than compute them from scratch.
20310-
func (c *Checker) observeHiddenMembers(t *Type) {
20311-
if i, ok := c.resolving.get(memoKeyOf(t, memoStructuredMembers)); ok && int(i) < c.visibleStart {
20312-
c.markResolutionCycle(c.visibleStart)
20313-
}
20314-
}
20315-
2031620306
// yieldCycleToMembers handles re-entering the type resolution in progress
2031720307
// at start, a cycle that would fail it, when the cycle passes through a
2031820308
// member table. Entering the cycle at the member table instead would not
@@ -21127,7 +21117,7 @@ func (c *Checker) isApplicableIndexType(source *Type, target *Type) bool {
2112721117
}
2112821118

2112921119
func (c *Checker) resolveStructuredTypeMembers(t *Type) *StructuredType {
21130-
if t.objectFlags&(ObjectFlagsMembersResolved|ObjectFlagsMembersResolving) == ObjectFlagsMembersResolved && !c.observingMemos {
21120+
if t.objectFlags&ObjectFlagsMembersResolved != 0 && !c.observingMemos {
2113121121
return t.asResolvedStructuredType()
2113221122
}
2113321123
return c.resolveStructuredTypeMembersSlow(t)
@@ -21137,12 +21127,16 @@ func (c *Checker) resolveStructuredTypeMembers(t *Type) *StructuredType {
2113721127
// past reading resolved members, out of line so that the rest inlines.
2113821128
func (c *Checker) resolveStructuredTypeMembersSlow(t *Type) *StructuredType {
2113921129
key := memoKeyOf(t, memoStructuredMembers)
21140-
if t.objectFlags&(ObjectFlagsMembersResolved|ObjectFlagsMembersResolving) == ObjectFlagsMembersResolved {
21130+
if t.objectFlags&ObjectFlagsMembersResolved != 0 {
2114121131
// Resolved members are only read.
2114221132
c.observeMemo(key)
2114321133
return t.AsStructuredType()
2114421134
}
21145-
if t.objectFlags&ObjectFlagsMembersResolving != 0 {
21135+
published := false
21136+
enclosing, inProgress := c.resolvingAnyIndex(key)
21137+
if !inProgress {
21138+
enclosing = -1
21139+
} else {
2114621140
// Resolving members may observe the type itself, whose members are
2114721141
// then incomplete.
2114821142
if c.isModuleTableType(t) {
@@ -21153,59 +21147,88 @@ func (c *Checker) resolveStructuredTypeMembersSlow(t *Type) *StructuredType {
2115321147
c.addCycleParticipants(start)
2115421148
}
2115521149
}
21156-
if len(c.cycleYields) != 0 {
21157-
c.observeHiddenMembers(t)
21150+
if j, ok := c.resolving.get(key); ok && int(j) < c.visibleStart {
21151+
// The members are being resolved below the cycle yield in
21152+
// progress, which then sees whatever part of them that
21153+
// resolution has published, rather than compute them from
21154+
// scratch, so the yield fails.
21155+
c.markResolutionCycle(c.visibleStart)
2115821156
}
21157+
published = c.resolutions[enclosing].membersPublished
2115921158
}
2116021159
c.beginMemo(key)
21161-
result := c.resolveStructuredTypeMembersUncached(t)
21160+
if !published {
21161+
c.resolveStructuredTypeMembersUncached(t, enclosing)
21162+
}
2116221163
c.endMemo()
21163-
return result
21164+
return t.AsStructuredType()
2116421165
}
2116521166

21166-
func (c *Checker) resolveStructuredTypeMembersUncached(t *Type) *StructuredType {
21167-
if t.objectFlags&ObjectFlagsMembersResolved == 0 {
21168-
if t.objectFlags&ObjectFlagsMembersResolving == 0 && c.isModuleTableType(t) {
21169-
c.resolveModuleTableMembers(t)
21170-
return t.AsStructuredType()
21167+
// resolveStructuredTypeMembersUncached resolves the members of t in the memo
21168+
// just begun for them. Many kinds of types make members available before
21169+
// they are complete, through publishStructuredTypeMembers, so the resolution
21170+
// is on the stack, but never fails. The members are resolved only once the
21171+
// outermost resolution of them completes. A nested one, which re-entering
21172+
// the members before any are available starts, makes its result available
21173+
// to the rest of the enclosing resolution at index enclosing, which may be
21174+
// hidden by a cycle yield.
21175+
func (c *Checker) resolveStructuredTypeMembersUncached(t *Type, enclosing int) {
21176+
outermost := enclosing < 0
21177+
if outermost && c.isModuleTableType(t) {
21178+
c.resolveModuleTableMembers(t)
21179+
return
21180+
}
21181+
c.beginTypeResolution(t, TypeSystemPropertyNameStructuredMembers)
21182+
defer func() {
21183+
c.popTypeResolution()
21184+
if outermost {
21185+
t.objectFlags |= ObjectFlagsMembersResolved
21186+
} else {
21187+
c.resolutions[enclosing].membersPublished = true
2117121188
}
21172-
// Many kinds of types make members available before they are
21173-
// complete, so the resolution is on the stack, but never fails.
21174-
outermost := t.objectFlags&ObjectFlagsMembersResolving == 0
21175-
t.objectFlags |= ObjectFlagsMembersResolving
21176-
c.beginTypeResolution(t, TypeSystemPropertyNameStructuredMembers)
21177-
defer func() {
21178-
c.popTypeResolution()
21179-
if outermost {
21180-
t.objectFlags &^= ObjectFlagsMembersResolving
21181-
}
21182-
if c.logResults() {
21183-
c.logMembersDiscard(t)
21184-
}
21185-
}()
21189+
if c.logResults() {
21190+
c.logMembersDiscard(t)
21191+
}
21192+
}()
21193+
switch {
21194+
case t.flags&TypeFlagsObject != 0:
2118621195
switch {
21187-
case t.flags&TypeFlagsObject != 0:
21188-
switch {
21189-
case t.objectFlags&(ObjectFlagsClassOrInterface|ObjectFlagsReference) != 0:
21190-
c.resolveObjectTypeMembers(t)
21191-
case t.objectFlags&ObjectFlagsReverseMapped != 0:
21192-
c.resolveReverseMappedTypeMembers(t)
21193-
case t.objectFlags&ObjectFlagsAnonymous != 0:
21194-
c.resolveAnonymousTypeMembers(t)
21195-
case t.objectFlags&ObjectFlagsMapped != 0:
21196-
c.resolveMappedTypeMembers(t)
21197-
default:
21198-
panic("Unhandled case in resolveStructuredTypeMembers")
21199-
}
21200-
case t.flags&TypeFlagsUnion != 0:
21201-
c.resolveUnionTypeMembers(t)
21202-
case t.flags&TypeFlagsIntersection != 0:
21203-
c.resolveIntersectionTypeMembers(t)
21196+
case t.objectFlags&(ObjectFlagsClassOrInterface|ObjectFlagsReference) != 0:
21197+
c.resolveObjectTypeMembers(t)
21198+
case t.objectFlags&ObjectFlagsReverseMapped != 0:
21199+
c.resolveReverseMappedTypeMembers(t)
21200+
case t.objectFlags&ObjectFlagsAnonymous != 0:
21201+
c.resolveAnonymousTypeMembers(t)
21202+
case t.objectFlags&ObjectFlagsMapped != 0:
21203+
c.resolveMappedTypeMembers(t)
2120421204
default:
2120521205
panic("Unhandled case in resolveStructuredTypeMembers")
2120621206
}
21207+
case t.flags&TypeFlagsUnion != 0:
21208+
c.resolveUnionTypeMembers(t)
21209+
case t.flags&TypeFlagsIntersection != 0:
21210+
c.resolveIntersectionTypeMembers(t)
21211+
default:
21212+
panic("Unhandled case in resolveStructuredTypeMembers")
2120721213
}
21208-
return t.AsStructuredType()
21214+
}
21215+
21216+
// markMembersPublished records that the members of t, whose resolution is
21217+
// in progress, are available to computations re-entering it.
21218+
func (c *Checker) markMembersPublished(t *Type) {
21219+
i, ok := c.resolvingAnyIndex(memoKeyOf(t, memoStructuredMembers))
21220+
debug.Assert(ok, "members published outside their resolution")
21221+
c.resolutions[i].membersPublished = true
21222+
}
21223+
21224+
// publishStructuredTypeMembers sets the members of t while they are being
21225+
// resolved, making them available to computations re-entering the resolution
21226+
// before it completes.
21227+
func (c *Checker) publishStructuredTypeMembers(t *Type, members ast.SymbolTable, callSignatures []*Signature, constructSignatures []*Signature, indexInfos []*IndexInfo) {
21228+
// Listing the properties may re-enter the resolution, which then sees
21229+
// the members.
21230+
c.markMembersPublished(t)
21231+
c.setStructuredTypeData(t, members, callSignatures, constructSignatures, indexInfos)
2120921232
}
2121021233

2121121234
// isModuleTableType reports whether t is the type of a module object, whose
@@ -21253,7 +21276,6 @@ func (c *Checker) resolveModuleTableMembers(t *Type) {
2125321276
mark := c.markDiscard()
2125421277
hidden := false
2125521278
for {
21256-
t.objectFlags |= ObjectFlagsMembersResolving
2125721279
c.beginTypeResolution(t, TypeSystemPropertyNameStructuredMembers)
2125821280
c.resolveAnonymousTypeMembers(t)
2125921281
r := c.topTypeResolution()
@@ -21268,11 +21290,13 @@ func (c *Checker) resolveModuleTableMembers(t *Type) {
2126821290
c.discardSince(mark)
2126921291
}
2127021292
c.popTypeResolution()
21271-
t.objectFlags &^= ObjectFlagsMembersResolving
2127221293
if canonical == nil && !restart {
2127321294
break
2127421295
}
2127521296
c.clearStructuredMembers(t)
21297+
key := memoKeyOf(t, memoStructuredMembers)
21298+
i, _ := c.resolving.get(key)
21299+
c.resolutions[i].membersPublished = false
2127621300
if canonical != nil {
2127721301
c.resolveStructuredTypeMembers(canonical.(*Type))
2127821302
continue
@@ -21281,12 +21305,12 @@ func (c *Checker) resolveModuleTableMembers(t *Type) {
2128121305
// is resolved again as if it had been entered first: with the
2128221306
// computations in progress below it hidden.
2128321307
hidden = true
21284-
floor, _ := c.resolving.get(memoKeyOf(t, memoStructuredMembers))
21285-
c.beginCycleYield(t, TypeSystemPropertyNameStructuredMembers, -1, int(floor))
21308+
c.beginCycleYield(t, TypeSystemPropertyNameStructuredMembers, -1, int(i))
2128621309
}
2128721310
if hidden {
2128821311
c.endCycleYield()
2128921312
}
21313+
t.objectFlags |= ObjectFlagsMembersResolved
2129021314
c.releaseDiscardMark(mark)
2129121315
if c.logResults() {
2129221316
c.logMembersDiscard(t)
@@ -21312,7 +21336,7 @@ func (c *Checker) clearStructuredMembers(t *Type) {
2131221336
//go:noinline
2131321337
func (c *Checker) logMembersDiscard(t *Type) {
2131421338
c.discardLog = append(c.discardLog, discardEntry{nil, func() {
21315-
if t.objectFlags&ObjectFlagsMembersResolving != 0 {
21339+
if _, ok := c.resolvingAnyIndex(memoKeyOf(t, memoStructuredMembers)); ok {
2131621340
// An enclosing resolution of the same members sets them again.
2131721341
return
2131821342
}
@@ -21398,7 +21422,7 @@ func (c *Checker) resolveObjectTypeMembers(t *Type) {
2139821422
return findIndexInfo(indexInfos, info.keyType) == nil
2139921423
}))
2140021424
}
21401-
c.setStructuredTypeMembers(t, nil, callSignatures, constructSignatures, indexInfos)
21425+
c.setStructuredTypeData(t, nil, callSignatures, constructSignatures, indexInfos)
2140221426
lazyState := c.lazyStateArena.New()
2140321427
lazyState.layout = layout
2140421428
lazyState.mapper = mapper
@@ -23101,22 +23125,22 @@ func (c *Checker) instantiateIndexInfo(info *IndexInfo, m *TypeMapper) *IndexInf
2310123125
func (c *Checker) resolveAnonymousTypeMembers(t *Type) {
2310223126
d := t.AsObjectType()
2310323127
if d.target != nil {
23104-
c.setStructuredTypeMembers(t, nil, nil, nil, nil)
23128+
c.publishStructuredTypeMembers(t, nil, nil, nil, nil)
2310523129
members := c.createInstantiatedSymbolTable(c.getPropertiesOfObjectType(d.target), d.mapper)
2310623130
callSignatures := c.instantiateSignatures(c.getSignaturesOfType(d.target, SignatureKindCall), d.mapper)
2310723131
constructSignatures := c.instantiateSignatures(c.getSignaturesOfType(d.target, SignatureKindConstruct), d.mapper)
2310823132
indexInfos := c.instantiateIndexInfos(c.getIndexInfosOfType(d.target), d.mapper)
23109-
c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
23133+
c.publishStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
2311023134
return
2311123135
}
2311223136
symbol := c.getMergedSymbol(t.symbol)
2311323137
if symbol.Flags()&ast.SymbolFlagsTypeLiteral != 0 {
23114-
c.setStructuredTypeMembers(t, nil, nil, nil, nil)
23138+
c.publishStructuredTypeMembers(t, nil, nil, nil, nil)
2311523139
members := c.getMembersOfSymbol(symbol)
2311623140
callSignatures := c.getSignaturesOfSymbol(members.Get(ast.InternalSymbolNameCall))
2311723141
constructSignatures := c.getSignaturesOfSymbol(members.Get(ast.InternalSymbolNameNew))
2311823142
indexInfos := c.getIndexInfosOfSymbol(symbol)
23119-
c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
23143+
c.publishStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
2312023144
return
2312123145
}
2312223146
// Combinations of function, class, enum and module
@@ -23132,14 +23156,14 @@ func (c *Checker) resolveAnonymousTypeMembers(t *Type) {
2313223156
members = varsOnly
2313323157
}
2313423158
var baseConstructorIndexInfo *IndexInfo
23135-
c.setStructuredTypeMembers(t, members, nil, nil, nil)
23159+
c.publishStructuredTypeMembers(t, members, nil, nil, nil)
2313623160
if symbol.Flags()&ast.SymbolFlagsClass != 0 {
2313723161
classType := c.getDeclaredTypeOfClassOrInterface(symbol)
2313823162
baseConstructorType := c.getBaseConstructorTypeOfClass(classType)
2313923163
if baseConstructorType.flags&(TypeFlagsObject|TypeFlagsIntersection|TypeFlagsTypeVariable) != 0 {
2314023164
members = members.Clone()
2314123165
c.addInheritedMembers(members, c.getPropertiesOfType(baseConstructorType))
23142-
c.setStructuredTypeMembers(t, members, nil, nil, nil)
23166+
c.publishStructuredTypeMembers(t, members, nil, nil, nil)
2314323167
} else if baseConstructorType == c.anyType {
2314423168
baseConstructorIndexInfo = c.anyBaseTypeIndexInfo
2314523169
}
@@ -23351,7 +23375,7 @@ func (c *Checker) resolveMappedTypeMembers(t *Type) {
2335123375
members := ast.NewSymbolTable()
2335223376
var indexInfos []*IndexInfo
2335323377
// Resolve upfront such that recursive references see an empty object type.
23354-
c.setStructuredTypeMembers(t, nil, nil, nil, nil)
23378+
c.publishStructuredTypeMembers(t, nil, nil, nil, nil)
2335523379
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
2335623380
// and T as the template type.
2335723381
typeParameter := c.getTypeParameterFromMappedType(t)
@@ -23434,7 +23458,7 @@ func (c *Checker) resolveMappedTypeMembers(t *Type) {
2343423458
} else {
2343523459
forEachType(c.getLowerBoundOfKeyType(constraintType), addMemberForKeyType)
2343623460
}
23437-
c.setStructuredTypeMembers(t, members, nil, nil, indexInfos)
23461+
c.publishStructuredTypeMembers(t, members, nil, nil, indexInfos)
2343823462
}
2343923463

2344023464
func (c *Checker) getTypeOfMappedSymbol(symbol *ast.Symbol) *Type {
@@ -23521,7 +23545,7 @@ func (c *Checker) resolveUnionTypeMembers(t *Type) {
2352123545
return c.getSignaturesOfType(t, SignatureKindConstruct)
2352223546
}))
2352323547
indexInfos := c.getUnionIndexInfos(t.Types())
23524-
c.setStructuredTypeMembers(t, nil, callSignatures, constructSignatures, indexInfos)
23548+
c.setStructuredTypeData(t, nil, callSignatures, constructSignatures, indexInfos)
2352523549
}
2352623550

2352723551
func (c *Checker) getArrayMemberCallSignatures(t *Type) []*Signature {
@@ -23785,7 +23809,7 @@ func (c *Checker) resolveIntersectionTypeMembers(t *Type) {
2378523809
indexInfos = c.appendIndexInfo(indexInfos, info, false /*union*/)
2378623810
}
2378723811
}
23788-
c.setStructuredTypeMembers(t, nil, callSignatures, constructSignatures, indexInfos)
23812+
c.setStructuredTypeData(t, nil, callSignatures, constructSignatures, indexInfos)
2378923813
}
2379023814

2379123815
func (c *Checker) appendSignatures(signatures []*Signature, newSignatures []*Signature) []*Signature {
@@ -28030,8 +28054,14 @@ func (c *Checker) cloneTypeReference(source *Type) *Type {
2803028054
return t
2803128055
}
2803228056

28057+
// setStructuredTypeMembers sets the members of a type being created, which
28058+
// are then resolved.
2803328059
func (c *Checker) setStructuredTypeMembers(t *Type, members ast.SymbolTable, callSignatures []*Signature, constructSignatures []*Signature, indexInfos []*IndexInfo) {
2803428060
t.objectFlags |= ObjectFlagsMembersResolved
28061+
c.setStructuredTypeData(t, members, callSignatures, constructSignatures, indexInfos)
28062+
}
28063+
28064+
func (c *Checker) setStructuredTypeData(t *Type, members ast.SymbolTable, callSignatures []*Signature, constructSignatures []*Signature, indexInfos []*IndexInfo) {
2803528065
data := t.AsStructuredType()
2803628066
data.members = members
2803728067
data.properties = c.getNamedMembers(members, t.symbol)

‎tsc/internal/checker/inference.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,7 @@ func (c *Checker) resolveReverseMappedTypeMembers(t *Type) {
11661166
}
11671167
members.Set(prop.Name(), inferredProp)
11681168
}
1169-
c.setStructuredTypeMembers(t, members, nil, nil, indexInfos)
1169+
c.setStructuredTypeData(t, members, nil, nil, indexInfos)
11701170
}
11711171

11721172
func (c *Checker) getTypeOfReverseMappedSymbol(symbol *ast.Symbol) *Type {

0 commit comments

Comments
 (0)