Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 43 additions & 16 deletions tsc/internal/checker/inference.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,10 @@ func (c *Checker) inferFromTypes(n *InferenceState, source *Type, target *Type)
return
}
if n.priority < inference.priority {
inference.candidates = nil
inference.contraCandidates = nil
clear(inference.candidates)
inference.candidates = inference.candidates[:0]
clear(inference.contraCandidates)
inference.contraCandidates = inference.contraCandidates[:0]
inference.topLevel = true
inference.priority = n.priority
}
Expand Down Expand Up @@ -379,8 +381,9 @@ func (c *Checker) invokeOnce(n *InferenceState, source *Type, target *Type, acti
}

func (c *Checker) inferFromMatchingTypes(n *InferenceState, sources []*Type, targets []*Type, matches func(c *Checker, s *Type, t *Type) bool, sort bool) ([]*Type, []*Type) {
var matchedSources []*Type
var matchedTargets []*Type
var matchedSourcesBuf, matchedTargetsBuf [8]*Type
matchedSources := matchedSourcesBuf[:0]
matchedTargets := matchedTargetsBuf[:0]
for _, t := range targets {
for _, s := range sources {
if matches(c, s, t) {
Expand Down Expand Up @@ -460,13 +463,21 @@ func (c *Checker) inferToMultipleTypes(n *InferenceState, source *Type, targets
typeVariableCount := 0
if targetFlags&TypeFlagsUnion != 0 {
var nakedTypeVariable *Type
var sourceBuf [1]*Type
var sources []*Type
if source.flags&TypeFlagsUnion != 0 {
sources = source.Types()
} else {
sources = []*Type{source}
sourceBuf[0] = source
sources = sourceBuf[:]
}
var matchedBuf [64]bool
var matched []bool
if len(sources) <= len(matchedBuf) {
matched = matchedBuf[:len(sources)]
} else {
matched = make([]bool, len(sources))
}
matched := make([]bool, len(sources))
inferenceCircularity := false
// First infer to types that are not naked type variables. For each source type we
// track whether inferences were made from that particular type to some target with
Expand Down Expand Up @@ -504,7 +515,8 @@ func (c *Checker) inferToMultipleTypes(n *InferenceState, source *Type, targets
// types from which no inferences have been made so far and infer from that union to the
// naked type variable.
if typeVariableCount == 1 && !inferenceCircularity {
var unmatched []*Type
var unmatchedBuf [8]*Type
unmatched := unmatchedBuf[:0]
for i, s := range sources {
if !matched[i] {
unmatched = append(unmatched, s)
Expand Down Expand Up @@ -569,8 +581,8 @@ func (c *Checker) inferToConditionalType(n *InferenceState, source *Type, target
c.inferFromTypes(n, getNonDistributedTypeParameter(c.getTrueTypeFromConditionalType(source)), c.getTrueTypeFromConditionalType(target))
c.inferFromTypes(n, getNonDistributedTypeParameter(c.getFalseTypeFromConditionalType(source)), c.getFalseTypeFromConditionalType(target))
} else {
targetTypes := []*Type{c.getTrueTypeFromConditionalType(target), c.getFalseTypeFromConditionalType(target)}
c.inferToMultipleTypesWithPriority(n, source, targetTypes, target.flags, core.IfElse(n.contravariant, InferencePriorityContravariantConditional, 0))
targetTypes := [2]*Type{c.getTrueTypeFromConditionalType(target), c.getFalseTypeFromConditionalType(target)}
c.inferToMultipleTypesWithPriority(n, source, targetTypes[:], target.flags, core.IfElse(n.contravariant, InferencePriorityContravariantConditional, 0))
}
}

Expand Down Expand Up @@ -841,19 +853,25 @@ func (c *Checker) inferFromProperties(n *InferenceState, source *Type, target *T
for _, targetProp := range properties {
sourceProp := c.getPropertyOfType(source, targetProp.Name())
if sourceProp != nil && !core.Some(sourceProp.Declarations(), c.isSkipDirectInferenceNode) {
c.inferFromTypes(n, c.removeMissingType(c.getTypeOfSymbol(sourceProp), sourceProp.Flags()&ast.SymbolFlagsOptional != 0), c.removeMissingType(c.getTypeOfSymbol(targetProp), targetProp.Flags()&ast.SymbolFlagsOptional != 0))
targetType := c.removeMissingType(c.getTypeOfSymbol(targetProp), targetProp.Flags()&ast.SymbolFlagsOptional != 0)
if c.couldContainTypeVariables(targetType) {
c.inferFromTypes(n, c.removeMissingType(c.getTypeOfSymbol(sourceProp), sourceProp.Flags()&ast.SymbolFlagsOptional != 0), targetType)
}
}
}
}

func (c *Checker) inferFromSignatures(n *InferenceState, source *Type, target *Type, kind SignatureKind) {
targetSignatures := c.getSignaturesOfType(target, kind)
targetLen := len(targetSignatures)
if targetLen == 0 {
return
}
sourceSignatures := c.getSignaturesOfType(source, kind)
sourceLen := len(sourceSignatures)
if sourceLen > 0 {
// We match source and target signatures from the bottom up, and if the source has fewer signatures
// than the target, we infer from the first source signature to the excess target signatures.
targetSignatures := c.getSignaturesOfType(target, kind)
targetLen := len(targetSignatures)
for i := range targetLen {
sourceIndex := max(sourceLen-targetLen+i, 0)
c.inferFromSignature(n, c.getBaseSignature(sourceSignatures[sourceIndex]), c.getErasedSignature(targetSignatures[i]))
Expand Down Expand Up @@ -889,17 +907,21 @@ func (c *Checker) applyToParameterTypes(source *Signature, target *Signature, ca
if sourceRestType == nil {
paramCount = min(sourceCount, targetNonRestCount)
}
// Callers only use the callback to infer to the target type, which is a no-op when the target cannot
// contain type variables, so we avoid computing the corresponding source types in that case.
sourceThisType := c.getThisTypeOfSignature(source)
if sourceThisType != nil {
targetThisType := c.getThisTypeOfSignature(target)
if targetThisType != nil {
if targetThisType != nil && c.couldContainTypeVariables(targetThisType) {
callback(sourceThisType, targetThisType)
}
}
for i := range paramCount {
callback(c.getTypeAtPosition(source, i), c.getTypeAtPosition(target, i))
if targetType := c.getTypeAtPosition(target, i); c.couldContainTypeVariables(targetType) {
callback(c.getTypeAtPosition(source, i), targetType)
}
}
if targetRestType != nil {
if targetRestType != nil && c.couldContainTypeVariables(targetRestType) {
callback(c.getRestTypeAtPosition(source, paramCount, c.isConstTypeVariable(targetRestType, 0) && !someType(targetRestType, c.isMutableArrayLikeType) /*readonly*/), targetRestType)
}
}
Expand All @@ -909,7 +931,9 @@ func (c *Checker) applyToReturnTypes(source *Signature, target *Signature, callb
if targetTypePredicate != nil {
sourceTypePredicate := c.getTypePredicateOfSignature(source)
if sourceTypePredicate != nil && c.typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.t != nil && targetTypePredicate.t != nil {
callback(sourceTypePredicate.t, targetTypePredicate.t)
if c.couldContainTypeVariables(targetTypePredicate.t) {
callback(sourceTypePredicate.t, targetTypePredicate.t)
}
return
}
}
Expand All @@ -926,6 +950,9 @@ func (c *Checker) inferFromIndexTypes(n *InferenceState, source *Type, target *T
priority = InferencePriorityHomomorphicMappedType
}
indexInfos := c.getIndexInfosOfType(target)
if len(indexInfos) == 0 {
return
}
if c.isObjectTypeWithInferableIndex(source) {
for _, targetInfo := range indexInfos {
var propTypes []*Type
Expand Down
Loading