Skip to content
Open
Show file tree
Hide file tree
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
107 changes: 53 additions & 54 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ type InferenceContext struct {
mapper *TypeMapper // Mapper that fixes inferences
nonFixingMapper *TypeMapper // Mapper that doesn't fix inferences
returnMapper *TypeMapper // Type mapper for inferences from return types (if any)
outerReturnMapper *TypeMapper // Type mapper for inferences from return types of outer function (if any)
inferredTypeParameters []*Type // Inferred type parameters for function result
intraExpressionInferenceSites []IntraExpressionInferenceSite
}
Expand Down Expand Up @@ -7298,15 +7299,15 @@ func (c *Checker) instantiateTypeWithSingleGenericCallSignature(node *ast.Node,
if !hasOverlappingInferences(context.inferences, inferences) {
c.mergeInferences(context.inferences, inferences)
context.inferredTypeParameters = core.Concatenate(context.inferredTypeParameters, uniqueTypeParameters)
return c.getOrCreateTypeFromSignature(instantiatedSignature, nil)
return c.getOrCreateTypeFromSignature(instantiatedSignature)
}
}
}
// TODO: The signature may reference any outer inference contexts, but we map pop off and then apply new inference contexts,
// and thus get different inferred types. That this is cached on the *first* such attempt is not currently an issue, since expression
// types *also* get cached on the first pass. If we ever properly speculate, though, the cached "isolatedSignatureType" signature
// field absolutely needs to be included in the list of speculative caches.
return c.getOrCreateTypeFromSignature(c.instantiateSignatureInContextOf(signature, contextualSignature, context, nil), c.getOuterInferenceTypeParameters())
return c.getOrCreateTypeFromSignature(c.instantiateSignatureInContextOf(signature, contextualSignature, context, nil))
}

func (c *Checker) getOuterInferenceTypeParameters() []*Type {
Expand Down Expand Up @@ -9164,7 +9165,7 @@ func (c *Checker) inferTypeArguments(node *ast.Node, signature *Signature, args
contextualSignature := c.getSingleCallSignature(instantiatedType)
var inferenceSourceType *Type
if contextualSignature != nil && len(contextualSignature.typeParameters) != 0 {
inferenceSourceType = c.getOrCreateTypeFromSignature(c.getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters), nil)
inferenceSourceType = c.getOrCreateTypeFromSignature(c.getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters))
} else {
inferenceSourceType = instantiatedType
}
Expand All @@ -9175,10 +9176,14 @@ func (c *Checker) inferTypeArguments(node *ast.Node, signature *Signature, args
// from the return type. We need a separate inference pass here because (a) instantiation of
// the source type uses the outer context's return mapper (which excludes inferences made from
// outer arguments), and (b) we don't want any further inferences going into this context.
// We use `createOuterReturnMapper` to ensure that all occurrences of outer type parameters are
// replaced with inferences produced from the outer return type or preceding outer arguments.
// This protects against circular inferences, i.e. avoiding situations where inferences reference
// type parameters for which the inferences are being made.
returnContext := c.newInferenceContext(signature.typeParameters, signature, context.flags, nil)
var outerReturnMapper *TypeMapper
if outerContext != nil {
outerReturnMapper = outerContext.returnMapper
outerReturnMapper = c.createOuterReturnMapper(outerContext)
}
returnSourceType := c.instantiateType(contextualType, outerReturnMapper)
c.inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType, InferencePriorityNone, false)
Expand Down Expand Up @@ -16316,6 +16321,9 @@ func (c *Checker) getConstraintOfType(t *Type) *Type {
}

func (c *Checker) getConstraintOfTypeParameter(typeParameter *Type) *Type {
if typeParameter.flags&TypeFlagsTypeParameter == 0 {
return nil
}
if c.hasNonCircularBaseConstraint(typeParameter) {
return c.getConstraintFromTypeParameter(typeParameter)
}
Expand Down Expand Up @@ -18447,8 +18455,10 @@ func (c *Checker) getSignatureInstantiation(sig *Signature, typeArguments []*Typ
if returnSignature != nil {
newReturnSignature := c.cloneSignature(returnSignature)
newReturnSignature.typeParameters = inferredTypeParameters
newReturnType := c.getOrCreateTypeFromSignature(newReturnSignature)
newReturnType.AsObjectType().mapper = instantiatedSignature.mapper
newInstantiatedSignature := c.cloneSignature(instantiatedSignature)
newInstantiatedSignature.resolvedReturnType = c.getOrCreateTypeFromSignature(newReturnSignature, nil)
newInstantiatedSignature.resolvedReturnType = newReturnType
return newInstantiatedSignature
}
}
Expand Down Expand Up @@ -18513,7 +18523,7 @@ func (c *Checker) getSingleSignature(t *Type, kind SignatureKind, allowMembers b
return nil
}

func (c *Checker) getOrCreateTypeFromSignature(sig *Signature, outerTypeParameters []*Type) *Type {
func (c *Checker) getOrCreateTypeFromSignature(sig *Signature) *Type {
// There are two ways to declare a construct signature, one is by declaring a class constructor
// using the constructor keyword, and the other is declaring a bare construct signature in an
// object type literal or interface (using the new keyword). Each way of declaring a constructor
Expand All @@ -18525,17 +18535,12 @@ func (c *Checker) getOrCreateTypeFromSignature(sig *Signature, outerTypeParamete
}
// If declaration is undefined, it is likely to be the signature of the default constructor.
isConstructor := kind == ast.KindUnknown || kind == ast.KindConstructor || kind == ast.KindConstructSignature || kind == ast.KindConstructorType
// The type must have a symbol with a `Function` flag and a declaration in order to be correctly flagged as possibly containing
// type variables by `couldContainTypeVariables`
t := c.newObjectType(ObjectFlagsAnonymous|ObjectFlagsSingleSignatureType, c.newSymbol(ast.SymbolFlagsFunction, ast.InternalSymbolNameFunction))
if sig.declaration != nil && !ast.NodeIsSynthesized(sig.declaration) {
t.symbol.Declarations = []*ast.Node{sig.declaration}
t.symbol.ValueDeclaration = sig.declaration
}
if outerTypeParameters == nil && sig.declaration != nil {
outerTypeParameters = c.getOuterTypeParameters(sig.declaration, true /*includeThisTypes*/)

var symbol *ast.Symbol
if sig.declaration != nil {
symbol = sig.declaration.Symbol()
}
t.AsSingleSignatureType().outerTypeParameters = outerTypeParameters
t := c.newObjectType(ObjectFlagsAnonymous|ObjectFlagsSingleSignatureType, symbol)
if isConstructor {
c.setStructuredTypeMembers(t, nil, nil, []*Signature{sig}, nil)
} else {
Expand Down Expand Up @@ -21182,6 +21187,9 @@ func (c *Checker) getDefaultTypeArgumentType(isInJavaScriptFile bool) *Type {
// this gets the instantiated default type of its target. If the type parameter has no default type or
// the default is circular, `undefined` is returned.
func (c *Checker) getDefaultFromTypeParameter(t *Type) *Type {
if t.flags&TypeFlagsTypeParameter == 0 {
return nil
}
defaultType := c.getResolvedTypeParameterDefault(t)
if defaultType != c.noConstraintType && defaultType != c.circularConstraintType {
return defaultType
Expand Down Expand Up @@ -21349,7 +21357,6 @@ func (c *Checker) couldContainTypeVariablesWorker(t *Type) bool {
}
result := t.flags&TypeFlagsInstantiable != 0 ||
t.flags&TypeFlagsObject != 0 && !c.isNonGenericTopLevelType(t) && (objectFlags&ObjectFlagsReference != 0 && (t.AsTypeReference().node != nil || core.Some(c.getTypeArguments(t), c.couldContainTypeVariables)) ||
objectFlags&ObjectFlagsSingleSignatureType != 0 && len(t.AsSingleSignatureType().outerTypeParameters) != 0 ||
objectFlags&ObjectFlagsAnonymous != 0 && t.symbol != nil && t.symbol.Flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsMethod|ast.SymbolFlagsClass|ast.SymbolFlagsTypeLiteral|ast.SymbolFlagsObjectLiteral) != 0 && t.symbol.Declarations != nil ||
objectFlags&(ObjectFlagsMapped|ObjectFlagsReverseMapped|ObjectFlagsObjectRestType|ObjectFlagsInstantiationExpressionType) != 0) ||
t.flags&TypeFlagsUnionOrIntersection != 0 && t.flags&TypeFlagsEnumLiteral == 0 && !c.isNonGenericTopLevelType(t) && core.Some(t.Types(), c.couldContainTypeVariables)
Expand Down Expand Up @@ -21458,9 +21465,9 @@ func (c *Checker) instantiateTypeWorker(t *Type, m *TypeMapper, alias *TypeAlias
// Handles instantiation of the following object types:
// AnonymousType (ObjectFlagsAnonymous)
// TypeReference with node != nil (ObjectFlagsReference)
// SingleSignatureType (ObjectFlagsSingleSignatureType)
// InstantiationExpressionType (ObjectFlagsInstantiationExpressionType)
// MappedType (ObjectFlagsMapped)
// Note: ObjectFlagsSingleSignatureType types are handled as anonymous types
func (c *Checker) getObjectTypeInstantiation(t *Type, m *TypeMapper, alias *TypeAlias) *Type {
var declaration *ast.Node
var target *Type
Expand All @@ -21482,34 +21489,30 @@ func (c *Checker) getObjectTypeInstantiation(t *Type, m *TypeMapper, alias *Type
default:
target = t
}
if t.objectFlags&ObjectFlagsSingleSignatureType != 0 {
typeParameters = t.AsSingleSignatureType().outerTypeParameters
} else {
typeParameters = links.outerTypeParameters
if typeParameters == nil {
// The first time an anonymous type is instantiated we compute and store a list of the type
// parameters that are in scope (and therefore potentially referenced). For type literals that
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
// set of type parameters to those that are possibly referenced in the literal.
typeParameters = c.getOuterTypeParameters(declaration, true /*includeThisTypes*/)
if len(target.alias.TypeArguments()) == 0 {
if t.objectFlags&(ObjectFlagsReference|ObjectFlagsInstantiationExpressionType) != 0 {
typeParameters = core.Filter(typeParameters, func(tp *Type) bool {
return c.isTypeParameterPossiblyReferenced(tp, declaration)
})
} else if target.symbol.Flags&(ast.SymbolFlagsMethod|ast.SymbolFlagsTypeLiteral) != 0 {
typeParameters = core.Filter(typeParameters, func(tp *Type) bool {
return core.Some(t.symbol.Declarations, func(d *ast.Node) bool {
return c.isTypeParameterPossiblyReferenced(tp, d)
})
typeParameters = links.outerTypeParameters
if typeParameters == nil {
// The first time an anonymous type is instantiated we compute and store a list of the type
// parameters that are in scope (and therefore potentially referenced). For type literals that
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
// set of type parameters to those that are possibly referenced in the literal.
typeParameters = c.getOuterTypeParameters(declaration, true /*includeThisTypes*/)
if len(target.alias.TypeArguments()) == 0 {
if t.objectFlags&(ObjectFlagsReference|ObjectFlagsInstantiationExpressionType) != 0 {
typeParameters = core.Filter(typeParameters, func(tp *Type) bool {
return c.isTypeParameterPossiblyReferenced(tp, declaration)
})
} else if target.symbol.Flags&(ast.SymbolFlagsMethod|ast.SymbolFlagsTypeLiteral) != 0 {
typeParameters = core.Filter(typeParameters, func(tp *Type) bool {
return core.Some(t.symbol.Declarations, func(d *ast.Node) bool {
return c.isTypeParameterPossiblyReferenced(tp, d)
})
}
}
if typeParameters == nil {
typeParameters = []*Type{}
})
}
links.outerTypeParameters = typeParameters
}
if typeParameters == nil {
typeParameters = []*Type{}
}
links.outerTypeParameters = typeParameters
}
if len(typeParameters) == 0 {
return t
Expand All @@ -21534,12 +21537,10 @@ func (c *Checker) getObjectTypeInstantiation(t *Type, m *TypeMapper, alias *Type
}
result := data.instantiations[key]
if result == nil {
if t.objectFlags&ObjectFlagsSingleSignatureType != 0 {
result = c.instantiateAnonymousType(t, m, nil /*alias*/)
data.instantiations[key] = result
return result
}
newMapper := newTypeMapper(typeParameters, typeArguments)
if target.objectFlags&ObjectFlagsSingleSignatureType != 0 && m != nil {
newMapper = c.combineTypeMappers(newMapper, m)
}
switch {
case target.objectFlags&ObjectFlagsReference != 0:
result = c.createDeferredTypeReference(t.Target(), t.AsTypeReference().node, newMapper, newAlias)
Expand Down Expand Up @@ -21635,8 +21636,6 @@ func (c *Checker) instantiateAnonymousType(t *Type, m *TypeMapper, alias *TypeAl
freshTypeParameter.AsTypeParameter().mapper = m
case t.objectFlags&ObjectFlagsInstantiationExpressionType != 0:
result.AsInstantiationExpressionType().node = t.AsInstantiationExpressionType().node
case t.objectFlags&ObjectFlagsSingleSignatureType != 0:
result.AsSingleSignatureType().outerTypeParameters = t.AsSingleSignatureType().outerTypeParameters
}
if alias == nil {
alias = c.instantiateTypeAlias(t.alias, m)
Expand Down Expand Up @@ -24161,7 +24160,7 @@ func (c *Checker) newObjectType(objectFlags ObjectFlags, symbol *ast.Symbol) *Ty
case objectFlags&ObjectFlagsInstantiationExpressionType != 0:
data = &InstantiationExpressionType{}
case objectFlags&ObjectFlagsSingleSignatureType != 0:
data = &SingleSignatureType{}
data = &ObjectType{}
case objectFlags&ObjectFlagsAnonymous != 0:
data = &ObjectType{}
default:
Expand Down Expand Up @@ -28447,7 +28446,7 @@ func (c *Checker) getContextualTypeForArgumentAtIndex(callTarget *ast.Node, argI
func (c *Checker) getContextualTypeForDecorator(decorator *ast.Node) *Type {
signature := c.getDecoratorCallSignature(decorator)
if signature != nil {
return c.getOrCreateTypeFromSignature(signature, nil)
return c.getOrCreateTypeFromSignature(signature)
}
return nil
}
Expand Down Expand Up @@ -28977,7 +28976,7 @@ func (c *Checker) getESDecoratorCallSignature(decorator *ast.Node) *Signature {
// instance, depending on whether the member was `static`.
var valueType *Type
if ast.IsMethodDeclaration(node) {
valueType = c.getOrCreateTypeFromSignature(c.getSignatureFromDeclaration(node), nil)
valueType = c.getOrCreateTypeFromSignature(c.getSignatureFromDeclaration(node))
} else {
valueType = c.getTypeOfNode(node)
}
Expand Down Expand Up @@ -29144,7 +29143,7 @@ func (c *Checker) newESDecoratorCallSignature(targetType *Type, contextType *Typ
// Creates a synthetic `FunctionType`
func (c *Checker) newFunctionType(typeParameters []*Type, thisParameter *ast.Symbol, parameters []*ast.Symbol, returnType *Type) *Type {
signature := c.newCallSignature(typeParameters, thisParameter, parameters, returnType)
return c.getOrCreateTypeFromSignature(signature, nil)
return c.getOrCreateTypeFromSignature(signature)
}

func (c *Checker) newGetterFunctionType(t *Type) *Type {
Expand Down
14 changes: 14 additions & 0 deletions internal/checker/inference.go
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,20 @@ func (c *Checker) getMapperFromContext(n *InferenceContext) *TypeMapper {
return n.mapper
}

// Return a type mapper that combines the context's return mapper with a mapper that erases any additional type parameters
// to their inferences at the time of creation.
func (c *Checker) createOuterReturnMapper(context *InferenceContext) *TypeMapper {
if context.outerReturnMapper == nil {
clonedMapper := c.getMapperFromContext(c.cloneInferenceContext(context, InferenceFlagsNone))
if context.returnMapper != nil {
context.outerReturnMapper = newMergedTypeMapper(context.returnMapper, clonedMapper)
} else {
context.outerReturnMapper = clonedMapper
}
}
return context.outerReturnMapper
}

func (c *Checker) getCovariantInference(inference *InferenceInfo, signature *Signature) *Type {
// Extract all object and array literal types and replace them with a single widened and normalized type.
candidates := c.unionObjectAndArrayLiteralCandidates(inference.candidates)
Expand Down
4 changes: 2 additions & 2 deletions internal/checker/jsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@ func (c *Checker) getStaticTypeOfReferencedJsxConstructor(context *ast.Node) *Ty
if isJsxIntrinsicTagName(context.TagName()) {
result := c.getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context)
fakeSignature := c.createSignatureForJSXIntrinsic(context, result)
return c.getOrCreateTypeFromSignature(fakeSignature, nil)
return c.getOrCreateTypeFromSignature(fakeSignature)
}
tagType := c.checkExpressionCached(context.TagName())
if tagType.flags&TypeFlagsStringLiteral != 0 {
Expand All @@ -1116,7 +1116,7 @@ func (c *Checker) getStaticTypeOfReferencedJsxConstructor(context *ast.Node) *Ty
return c.errorType
}
fakeSignature := c.createSignatureForJSXIntrinsic(context, result)
return c.getOrCreateTypeFromSignature(fakeSignature, nil)
return c.getOrCreateTypeFromSignature(fakeSignature)
}
return tagType
}
Expand Down
2 changes: 1 addition & 1 deletion internal/checker/nodebuilderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2376,7 +2376,7 @@ func (b *nodeBuilderImpl) createTypeNodeFromObjectType(t *Type) *ast.TypeNode {
})
if len(abstractSignatures) > 0 {
types := core.Map(abstractSignatures, func(s *Signature) *Type {
return b.ch.getOrCreateTypeFromSignature(s, nil)
return b.ch.getOrCreateTypeFromSignature(s)
})
// count the number of type elements excluding abstract constructors
typeElementCount := len(callSigs) + (len(ctorSigs) - len(abstractSignatures)) + len(resolved.indexInfos) + (core.IfElse(b.ctx.flags&nodebuilder.FlagsWriteClassExpressionAsTypeLiteral != 0, core.CountWhere(resolved.properties, func(p *ast.Symbol) bool {
Expand Down
20 changes: 5 additions & 15 deletions internal/checker/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,11 +574,10 @@ func (t *Type) ObjectFlags() ObjectFlags {

// Casts for concrete struct types

func (t *Type) AsIntrinsicType() *IntrinsicType { return t.data.(*IntrinsicType) }
func (t *Type) AsLiteralType() *LiteralType { return t.data.(*LiteralType) }
func (t *Type) AsUniqueESSymbolType() *UniqueESSymbolType { return t.data.(*UniqueESSymbolType) }
func (t *Type) AsTupleType() *TupleType { return t.data.(*TupleType) }
func (t *Type) AsSingleSignatureType() *SingleSignatureType { return t.data.(*SingleSignatureType) }
func (t *Type) AsIntrinsicType() *IntrinsicType { return t.data.(*IntrinsicType) }
func (t *Type) AsLiteralType() *LiteralType { return t.data.(*LiteralType) }
func (t *Type) AsUniqueESSymbolType() *UniqueESSymbolType { return t.data.(*UniqueESSymbolType) }
func (t *Type) AsTupleType() *TupleType { return t.data.(*TupleType) }
func (t *Type) AsInstantiationExpressionType() *InstantiationExpressionType {
return t.data.(*InstantiationExpressionType)
}
Expand Down Expand Up @@ -838,9 +837,7 @@ func (t *StructuredType) Properties() []*ast.Symbol {
// ObjectFlagsAnonymous|ObjectFlagsInstantiationExpression: Originating instantiation expression type
// ObjectFlagsAnonymous|ObjectFlagsInstantiated|ObjectFlagsInstantiationExpression: Instantiated instantiation expression type

// SingleSignatureType:
// ObjectFlagsAnonymous|ObjectFlagsSingleSignatureType: Originating single signature type
// ObjectFlagsAnonymous|ObjectFlagsInstantiated|ObjectFlagsSingleSignatureType: Instantiated single signature type
// Note: ObjectFlagsSingleSignatureType types are AnonymousType with the flag set (no separate struct)

// ReverseMappedType:
// ObjectFlagsAnonymous|ObjectFlagsReverseMapped: Reverse mapped type
Expand Down Expand Up @@ -948,13 +945,6 @@ func (t *TupleType) ElementFlags() []ElementFlags {
return elementFlags
}

// SingleSignatureType

type SingleSignatureType struct {
ObjectType
outerTypeParameters []*Type
}

// InstantiationExpressionType

type InstantiationExpressionType struct {
Expand Down
3 changes: 0 additions & 3 deletions internal/testrunner/compiler_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,6 @@ var skippedTests = []string{
"noImplicitUseStrict_amd.ts",
"noImplicitAnyIndexingSuppressed.ts",
"excessPropertyErrorsSuppressed.ts",

// Broken
"inferenceFromGenericClassNoCrash1.ts",
}

func (r *CompilerBaselineRunner) RunTests(t *testing.T) {
Expand Down
Loading