MCPcopy Index your code
hub / github.com/microsoft/typescript-go / getTypeAtFlowBranchLabel

Method getTypeAtFlowBranchLabel

internal/checker/flow.go:1232–1288  ·  view source on GitHub ↗
(f *FlowState, flow *ast.FlowNode, antecedents *ast.FlowList)

Source from the content-addressed store, hash-verified

1230}
1231
1232func (c *Checker) getTypeAtFlowBranchLabel(f *FlowState, flow *ast.FlowNode, antecedents *ast.FlowList) FlowType {
1233 antecedentStart := len(c.antecedentTypes)
1234 subtypeReduction := false
1235 seenIncomplete := false
1236 var bypassFlow *ast.FlowNode
1237 for list := antecedents; list != nil; list = list.Next {
1238 antecedent := list.Flow
1239 if bypassFlow == nil && antecedent.Flags&ast.FlowFlagsSwitchClause != 0 && antecedent.Node.AsFlowSwitchClauseData().IsEmpty() {
1240 // The antecedent is the bypass branch of a potentially exhaustive switch statement.
1241 bypassFlow = antecedent
1242 continue
1243 }
1244 flowType := c.getTypeAtFlowNode(f, antecedent)
1245 // If the type at a particular antecedent path is the declared type and the
1246 // reference is known to always be assigned (i.e. when declared and initial types
1247 // are the same), there is no reason to process more antecedents since the only
1248 // possible outcome is subtypes that will be removed in the final union type anyway.
1249 if flowType.t == f.declaredType && f.declaredType == f.initialType {
1250 c.antecedentTypes = c.antecedentTypes[:antecedentStart]
1251 return FlowType{t: flowType.t}
1252 }
1253 if !slices.Contains(c.antecedentTypes[antecedentStart:], flowType.t) {
1254 c.antecedentTypes = append(c.antecedentTypes, flowType.t)
1255 }
1256 // If an antecedent type is not a subset of the declared type, we need to perform
1257 // subtype reduction. This happens when a "foreign" type is injected into the control
1258 // flow using the instanceof operator or a user defined type predicate.
1259 if !c.isTypeSubsetOf(flowType.t, f.initialType) {
1260 subtypeReduction = true
1261 }
1262 if flowType.incomplete {
1263 seenIncomplete = true
1264 }
1265 }
1266 if bypassFlow != nil {
1267 flowType := c.getTypeAtFlowNode(f, bypassFlow)
1268 // If the bypass flow contributes a type we haven't seen yet and the switch statement
1269 // isn't exhaustive, process the bypass flow type. Since exhaustiveness checks increase
1270 // the risk of circularities, we only want to perform them when they make a difference.
1271 if flowType.t.flags&TypeFlagsNever == 0 && !slices.Contains(c.antecedentTypes[antecedentStart:], flowType.t) && !c.isExhaustiveSwitchStatement(bypassFlow.Node.AsFlowSwitchClauseData().SwitchStatement) {
1272 if flowType.t == f.declaredType && f.declaredType == f.initialType {
1273 c.antecedentTypes = c.antecedentTypes[:antecedentStart]
1274 return FlowType{t: flowType.t}
1275 }
1276 c.antecedentTypes = append(c.antecedentTypes, flowType.t)
1277 if !c.isTypeSubsetOf(flowType.t, f.initialType) {
1278 subtypeReduction = true
1279 }
1280 if flowType.incomplete {
1281 seenIncomplete = true
1282 }
1283 }
1284 }
1285 result := c.newFlowType(c.getUnionOrEvolvingArrayType(f, c.antecedentTypes[antecedentStart:], core.IfElse(subtypeReduction, UnionReductionSubtype, UnionReductionLiteral)), seenIncomplete)
1286 c.antecedentTypes = c.antecedentTypes[:antecedentStart]
1287 return result
1288}
1289

Callers 1

getTypeAtFlowNodeMethod · 0.95

Calls 11

getTypeAtFlowNodeMethod · 0.95
isTypeSubsetOfMethod · 0.95
newFlowTypeMethod · 0.95
IfElseFunction · 0.92
lenFunction · 0.85
ContainsMethod · 0.65
appendFunction · 0.50
IsEmptyMethod · 0.45

Tested by

no test coverage detected