Skip to content
Merged
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
110 changes: 62 additions & 48 deletions internal/ast/ast.go

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions internal/ast/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -3281,6 +3281,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsMethodDeclaration().FullSignature,
node.Body(),
)
case KindConstructor:
Expand All @@ -3290,6 +3291,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsConstructorDeclaration().FullSignature,
node.Body(),
)
case KindGetAccessor:
Expand All @@ -3300,6 +3302,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsGetAccessorDeclaration().FullSignature,
node.Body(),
)
case KindSetAccessor:
Expand All @@ -3310,6 +3313,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsSetAccessorDeclaration().FullSignature,
node.Body(),
)
case KindIndexSignature:
Expand All @@ -3328,6 +3332,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsFunctionExpression().FullSignature,
node.Body(),
)
case KindArrowFunction:
Expand All @@ -3337,6 +3342,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsArrowFunction().FullSignature,
node.AsArrowFunction().EqualsGreaterThanToken,
node.Body(),
)
Expand Down Expand Up @@ -3364,6 +3370,7 @@ func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierL
node.TypeParameterList(),
node.ParameterList(),
node.Type(),
node.AsFunctionDeclaration().FullSignature,
node.Body(),
)
case KindClassDeclaration:
Expand Down
71 changes: 70 additions & 1 deletion internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -3241,6 +3241,14 @@ func (c *Checker) checkFunctionOrMethodDeclaration(node *ast.Node) {
body := node.Body()
c.checkSourceElement(body)
c.checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, c.getReturnTypeFromAnnotation(node))
if node.FunctionLikeData().FullSignature != nil {
if c.getContextualCallSignature(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature), node) == nil {
c.error(node.FunctionLikeData().FullSignature, diagnostics.A_JSDoc_type_tag_on_a_function_must_have_a_signature_with_the_correct_number_of_arguments)
}
if node.Type() != nil || core.Some(node.Parameters(), func(p *ast.Node) bool { return p.Type() != nil }) {
c.error(node.FunctionLikeData().FullSignature, diagnostics.A_JSDoc_type_tag_may_not_occur_with_a_param_or_returns_tag)
}
}
if node.Type() == nil {
// Report an implicit any error if there is no body, no explicit return type, and node is not a private method
// in an ambient context
Expand Down Expand Up @@ -3532,7 +3540,15 @@ func (c *Checker) checkAllCodePathsInNonVoidFunctionReturnOrThrow(fn *ast.Node,
return
}
hasExplicitReturn := fn.Flags&ast.NodeFlagsHasExplicitReturn != 0
errorNode := core.OrElse(fn.Type(), fn)
errorNode := fn.Type()
if errorNode == nil {
if data := fn.FunctionLikeData(); data != nil && data.FullSignature != nil {
errorNode = data.FullSignature
}
}
if errorNode == nil {
errorNode = fn
}
switch {
case t != nil && t.flags&TypeFlagsNever != 0:
c.error(errorNode, diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point)
Expand Down Expand Up @@ -9754,6 +9770,14 @@ func (c *Checker) checkFunctionExpressionOrObjectLiteralMethod(node *ast.Node, c
if !hasGrammarError && ast.IsFunctionExpression(node) {
c.checkGrammarForGenerator(node)
}
if node.FunctionLikeData().FullSignature != nil {
if c.getContextualCallSignature(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature), node) == nil {
c.error(node.FunctionLikeData().FullSignature, diagnostics.A_JSDoc_type_tag_on_a_function_must_have_a_signature_with_the_correct_number_of_arguments)
}
if node.Type() != nil || core.Some(node.Parameters(), func(p *ast.Node) bool { return p.Type() != nil }) {
c.error(node.FunctionLikeData().FullSignature, diagnostics.A_JSDoc_type_tag_may_not_occur_with_a_param_or_returns_tag)
}
}
c.contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node, checkMode)
return c.getTypeOfSymbol(c.getSymbolOfDeclaration(node))
}
Expand Down Expand Up @@ -11593,6 +11617,11 @@ func (c *Checker) TryGetThisTypeAtEx(node *ast.Node, includeGlobalThis bool, con
}
if ast.IsFunctionLike(container) && (!c.isInParameterInitializerBeforeContainingFunction(node) || ast.GetThisParameter(container) != nil) {
thisType := c.getThisTypeOfDeclaration(container)
if thisType == nil && ast.IsInJSFile(container) {
if sig := c.getSignatureOfFullSignatureType(container); sig != nil {
thisType = c.getThisTypeOfSignature(sig)
}
}
// Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated.
// If this is a function in a JS file, it might be a class method.
if thisType == nil {
Expand Down Expand Up @@ -15935,6 +15964,9 @@ func (c *Checker) getTypeForVariableLikeDeclaration(declaration *ast.Node, inclu
return c.getReturnTypeOfSignature(getterSignature)
}
}
if t := c.getParameterTypeOfFullSignature(fn, declaration); t != nil {
return t
}
// Use contextual parameter type if one is available
var t *Type
if declaration.Symbol().Name == ast.InternalSymbolNameThis {
Expand Down Expand Up @@ -18906,6 +18938,12 @@ func (c *Checker) getSignaturesOfSymbol(symbol *ast.Symbol) []*Signature {
}
// If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters.
// Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would suppress checks that the two are compatible.
if ast.IsFunctionExpressionOrArrowFunction(decl) || ast.IsObjectLiteralMethod(decl) {
if sig := c.getSignatureOfFullSignatureType(decl); sig != nil {
result = append(result, sig)
continue
}
}
result = append(result, c.getSignatureFromDeclaration(decl))
}
return result
Expand Down Expand Up @@ -18984,6 +19022,11 @@ func (c *Checker) getTypeParametersFromDeclaration(declaration *ast.Node) []*Typ
for _, node := range declaration.TypeParameters() {
result = core.AppendIfUnique(result, c.getDeclaredTypeOfTypeParameter(node.Symbol()))
}
if len(result) == 0 && ast.IsFunctionDeclaration(declaration) {
if sig := c.getSignatureOfFullSignatureType(declaration); sig != nil {
return sig.TypeParameters()
}
}
return result
}

Expand Down Expand Up @@ -19133,6 +19176,32 @@ func (c *Checker) getReturnTypeFromAnnotation(declaration *ast.Node) *Type {
if ast.IsGetAccessorDeclaration(declaration) && c.hasBindableName(declaration) {
return c.getAnnotatedAccessorType(ast.GetDeclarationOfKind(c.getSymbolOfDeclaration(declaration), ast.KindSetAccessor))
}
return c.getReturnTypeOfFullSignature(declaration)
}

func (c *Checker) getSignatureOfFullSignatureType(node *ast.Node) *Signature {
if ast.IsInJSFile(node) && ast.IsFunctionLike(node) && node.FunctionLikeData().FullSignature != nil {
return c.getSingleCallSignature(c.getTypeFromTypeNode(node.FunctionLikeData().FullSignature))
}
return nil
}

func (c *Checker) getParameterTypeOfFullSignature(node *ast.Node, parameter *ast.ParameterDeclarationNode) *Type {
if signature := c.getSignatureOfFullSignatureType(node); signature != nil {
pos := slices.Index(node.Parameters(), parameter)
if parameter.AsParameterDeclaration().DotDotDotToken != nil {
return c.getRestTypeAtPosition(signature, pos, false /*readonly*/)
} else {
return c.getTypeAtPosition(signature, pos)
}
}
return nil
}

func (c *Checker) getReturnTypeOfFullSignature(node *ast.Node) *Type {
if signature := c.getSignatureOfFullSignatureType(node); signature != nil {
return c.getReturnTypeOfSignature(signature)
}
return nil
}

Expand Down
12 changes: 12 additions & 0 deletions internal/checker/emitresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,18 @@ func (r *emitResolver) CreateReturnTypeOfSignatureDeclaration(emitContext *print
return requestNodeBuilder.SerializeReturnTypeForSignature(original, enclosingDeclaration, flags, internalFlags, tracker)
}

func (r *emitResolver) CreateTypeParametersOfSignatureDeclaration(emitContext *printer.EmitContext, signatureDeclaration *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) []*ast.Node {
original := emitContext.ParseNode(signatureDeclaration)
if original == nil {
return nil
}

r.checkerMu.Lock()
defer r.checkerMu.Unlock()
requestNodeBuilder := NewNodeBuilder(r.checker, emitContext) // TODO: cache per-context
return requestNodeBuilder.SerializeTypeParametersForSignature(original, enclosingDeclaration, flags, internalFlags, tracker)
}

func (r *emitResolver) CreateTypeOfDeclaration(emitContext *printer.EmitContext, declaration *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
original := emitContext.ParseNode(declaration)
if original == nil {
Expand Down
7 changes: 7 additions & 0 deletions internal/checker/nodebuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ func (b *NodeBuilder) SerializeReturnTypeForSignature(signatureDeclaration *ast.
return b.exitContext(b.impl.serializeInferredReturnTypeForSignature(signature, returnType))
}

func (b *NodeBuilder) SerializeTypeParametersForSignature(signatureDeclaration *ast.Node, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) []*ast.Node {
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
symbol := b.impl.ch.getSymbolOfDeclaration(signatureDeclaration)
typeParams := b.SymbolToTypeParameterDeclarations(symbol, enclosingDeclaration, flags, internalFlags, tracker)
return b.exitContextSlice(typeParams)
}

// SerializeTypeForDeclaration implements NodeBuilderInterface.
func (b *NodeBuilder) SerializeTypeForDeclaration(declaration *ast.Node, symbol *ast.Symbol, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, internalFlags nodebuilder.InternalFlags, tracker nodebuilder.SymbolTracker) *ast.Node {
b.enterContext(enclosingDeclaration, flags, internalFlags, tracker)
Expand Down
20 changes: 13 additions & 7 deletions internal/checker/nodebuilderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -1526,6 +1526,12 @@ func (b *nodeBuilderImpl) typeParametersToTypeParameterDeclarations(symbol *ast.
results = append(results, b.typeParameterToDeclaration(param))
}
return results
} else if targetSymbol.Flags&ast.SymbolFlagsFunction != 0 {
var results []*ast.Node
for _, param := range b.ch.getTypeParametersFromDeclaration(symbol.ValueDeclaration) {
results = append(results, b.typeParameterToDeclaration(param))
}
return results
}
return nil
}
Expand Down Expand Up @@ -1760,13 +1766,13 @@ func (b *nodeBuilderImpl) signatureToSignatureDeclarationHelper(signature *Signa
}
node = b.f.NewMethodSignatureDeclaration(modifierList, name, questionToken, typeParamList, paramList, returnTypeNode)
case kind == ast.KindMethodDeclaration:
node = b.f.NewMethodDeclaration(modifierList, nil /*asteriskToken*/, name, nil /*questionToken*/, typeParamList, paramList, returnTypeNode, nil /*body*/)
node = b.f.NewMethodDeclaration(modifierList, nil /*asteriskToken*/, name, nil /*questionToken*/, typeParamList, paramList, returnTypeNode, nil /*fullSignature*/, nil /*body*/)
case kind == ast.KindConstructor:
node = b.f.NewConstructorDeclaration(modifierList, nil /*typeParamList*/, paramList, nil /*returnTypeNode*/, nil /*body*/)
node = b.f.NewConstructorDeclaration(modifierList, nil /*typeParamList*/, paramList, nil /*returnTypeNode*/, nil /*fullSignature*/, nil /*body*/)
case kind == ast.KindGetAccessor:
node = b.f.NewGetAccessorDeclaration(modifierList, name, nil /*typeParamList*/, paramList, returnTypeNode, nil /*body*/)
node = b.f.NewGetAccessorDeclaration(modifierList, name, nil /*typeParamList*/, paramList, returnTypeNode, nil /*fullSignature*/, nil /*body*/)
case kind == ast.KindSetAccessor:
node = b.f.NewSetAccessorDeclaration(modifierList, name, nil /*typeParamList*/, paramList, nil /*returnTypeNode*/, nil /*body*/)
node = b.f.NewSetAccessorDeclaration(modifierList, name, nil /*typeParamList*/, paramList, nil /*returnTypeNode*/, nil /*fullSignature*/, nil /*body*/)
case kind == ast.KindIndexSignature:
node = b.f.NewIndexSignatureDeclaration(modifierList, paramList, returnTypeNode)
// !!! JSDoc Support
Expand All @@ -1784,12 +1790,12 @@ func (b *nodeBuilderImpl) signatureToSignatureDeclarationHelper(signature *Signa
node = b.f.NewConstructorTypeNode(modifierList, typeParamList, paramList, returnTypeNode)
case kind == ast.KindFunctionDeclaration:
// TODO: assert name is Identifier
node = b.f.NewFunctionDeclaration(modifierList, nil /*asteriskToken*/, name, typeParamList, paramList, returnTypeNode, nil /*body*/)
node = b.f.NewFunctionDeclaration(modifierList, nil /*asteriskToken*/, name, typeParamList, paramList, returnTypeNode, nil /*fullSignature*/, nil /*body*/)
case kind == ast.KindFunctionExpression:
// TODO: assert name is Identifier
node = b.f.NewFunctionExpression(modifierList, nil /*asteriskToken*/, name, typeParamList, paramList, returnTypeNode, b.f.NewBlock(b.f.NewNodeList([]*ast.Node{}), false))
node = b.f.NewFunctionExpression(modifierList, nil /*asteriskToken*/, name, typeParamList, paramList, returnTypeNode, nil /*fullSignature*/, b.f.NewBlock(b.f.NewNodeList([]*ast.Node{}), false))
case kind == ast.KindArrowFunction:
node = b.f.NewArrowFunction(modifierList, typeParamList, paramList, returnTypeNode, nil /*equalsGreaterThanToken*/, b.f.NewBlock(b.f.NewNodeList([]*ast.Node{}), false))
node = b.f.NewArrowFunction(modifierList, typeParamList, paramList, returnTypeNode, nil /*fullSignature*/, nil /*equalsGreaterThanToken*/, b.f.NewBlock(b.f.NewNodeList([]*ast.Node{}), false))
default:
panic("Unhandled kind in signatureToSignatureDeclarationHelper")
}
Expand Down
8 changes: 8 additions & 0 deletions internal/checker/relater.go
Original file line number Diff line number Diff line change
Expand Up @@ -1999,11 +1999,19 @@ func (c *Checker) getTypePredicateOfSignature(sig *Signature) *TypePredicate {
default:
if sig.declaration != nil {
typeNode := sig.declaration.Type()
var jsdocTypePredicate *TypePredicate
if typeNode == nil {
if jsdocSignature := c.getSignatureOfFullSignatureType(sig.declaration); jsdocSignature != nil {
jsdocTypePredicate = c.getTypePredicateOfSignature(jsdocSignature)
}
}
switch {
case typeNode != nil:
if ast.IsTypePredicateNode(typeNode) {
sig.resolvedTypePredicate = c.createTypePredicateFromTypePredicateNode(typeNode, sig)
}
case jsdocTypePredicate != nil:
sig.resolvedTypePredicate = jsdocTypePredicate
case ast.IsFunctionLikeDeclaration(sig.declaration) && (sig.resolvedReturnType == nil || sig.resolvedReturnType.flags&TypeFlagsBoolean != 0) && c.getParameterCount(sig) > 0:
sig.resolvedTypePredicate = c.noTypePredicate // avoid infinite loop
sig.resolvedTypePredicate = c.getTypePredicateFromBody(sig.declaration)
Expand Down
4 changes: 3 additions & 1 deletion internal/diagnostics/diagnostics_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions internal/diagnostics/extraDiagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@
"Non-relative paths are not allowed. Did you forget a leading './'?": {
"category": "Error",
"code": 5090
},
"A JSDoc '@type' tag on a function must have a signature with the correct number of arguments.": {
"category": "Error",
"code": 8030
},
"A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag.": {
"category": "Error",
"code": 8040
}
}
Loading
Loading