diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 0ff050b0a7..79aa363d35 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -3257,9 +3257,6 @@ func (c *Checker) checkFunctionOrMethodDeclaration(node *ast.Node) { 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 @@ -9830,9 +9827,6 @@ func (c *Checker) checkFunctionExpressionOrObjectLiteralMethod(node *ast.Node, c 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)) @@ -11678,12 +11672,11 @@ func (c *Checker) TryGetThisTypeAtEx(node *ast.Node, includeGlobalThis bool, con container = c.getThisContainer(node, false /*includeArrowFunctions*/, false /*includeClassComputedPropertyName*/) } 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) - } + sig := c.getSignatureOfFullSignatureType(container) + if sig == nil { + sig = c.getSignatureFromDeclaration(container) } + 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 { @@ -11782,10 +11775,6 @@ func (c *Checker) isInParameterInitializerBeforeContainingFunction(node *ast.Nod return false } -func (c *Checker) getThisTypeOfDeclaration(declaration *ast.Node) *Type { - return c.getThisTypeOfSignature(c.getSignatureFromDeclaration(declaration)) -} - func (c *Checker) checkThisInStaticClassFieldInitializerInDecoratedClass(thisExpression *ast.Node, container *ast.Node) { if ast.IsPropertyDeclaration(container) && ast.HasStaticModifier(container) && c.legacyDecorators { initializer := container.Initializer() @@ -19091,11 +19080,11 @@ 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 sig := c.getSignatureOfFullSignatureType(decl); sig != nil { - result = append(result, sig) - continue + sig := c.getSignatureOfFullSignatureType(decl) + if sig == nil { + sig = c.getSignatureFromDeclaration(decl) } - result = append(result, c.getSignatureFromDeclaration(decl)) + result = append(result, sig) } return result } @@ -19177,15 +19166,13 @@ func (c *Checker) getSignatureFromDeclaration(declaration *ast.Node) *Signature } func (c *Checker) getTypeParametersFromDeclaration(declaration *ast.Node) []*Type { + if sig := c.getSignatureOfFullSignatureType(declaration); sig != nil { + return sig.TypeParameters() + } var result []*Type 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 } diff --git a/internal/checker/relater.go b/internal/checker/relater.go index 4f101352ff..5011c9b8cb 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -1994,19 +1994,11 @@ 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) diff --git a/internal/diagnostics/diagnostics_generated.go b/internal/diagnostics/diagnostics_generated.go index 9c9757528d..8f62d2b8d2 100644 --- a/internal/diagnostics/diagnostics_generated.go +++ b/internal/diagnostics/diagnostics_generated.go @@ -3518,8 +3518,6 @@ var Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear var A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag = &Message{code: 8039, category: CategoryError, key: "A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag_8039", text: "A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag"} -var A_JSDoc_type_tag_may_not_occur_with_a_param_or_returns_tag = &Message{code: 8040, category: CategoryError, key: "A_JSDoc_type_tag_may_not_occur_with_a_param_or_returns_tag_8040", text: "A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag."} - var Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit = &Message{code: 9005, category: CategoryError, key: "Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_9005", text: "Declaration emit for this file requires using private name '{0}'. An explicit type annotation may unblock declaration emit."} var Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit = &Message{code: 9006, category: CategoryError, key: "Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotati_9006", text: "Declaration emit for this file requires using private name '{0}' from module '{1}'. An explicit type annotation may unblock declaration emit."} diff --git a/internal/diagnostics/extraDiagnosticMessages.json b/internal/diagnostics/extraDiagnosticMessages.json index b735a67695..109a1bdfd5 100644 --- a/internal/diagnostics/extraDiagnosticMessages.json +++ b/internal/diagnostics/extraDiagnosticMessages.json @@ -19,10 +19,6 @@ "category": "Error", "code": 8030 }, - "A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag.": { - "category": "Error", - "code": 8040 - }, "Failed to delete file '{0}'.": { "category": "Message", "code": 6353 diff --git a/internal/parser/reparser.go b/internal/parser/reparser.go index 446e461985..7100a120eb 100644 --- a/internal/parser/reparser.go +++ b/internal/parser/reparser.go @@ -336,7 +336,7 @@ func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) } if fun, ok := getFunctionLikeHost(parent); ok { noTypedParams := core.Every(fun.Parameters(), func(param *ast.Node) bool { return param.Type() == nil }) - if fun.Type() == nil && noTypedParams && tag.AsJSDocTypeTag().TypeExpression != nil { + if fun.TypeParameterList() == nil && fun.Type() == nil && noTypedParams && tag.AsJSDocTypeTag().TypeExpression != nil { fun.FunctionLikeData().FullSignature = p.factory.DeepCloneReparse(tag.AsJSDocTypeTag().TypeExpression.Type()) p.finishMutatedNode(fun) } @@ -389,7 +389,7 @@ func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) } case ast.KindJSDocTemplateTag: if fun, ok := getFunctionLikeHost(parent); ok { - if fun.TypeParameters() == nil { + if fun.TypeParameters() == nil && fun.FunctionLikeData().FullSignature == nil { fun.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) p.finishMutatedNode(fun) } @@ -407,7 +407,7 @@ func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) } } case ast.KindJSDocParameterTag: - if fun, ok := getFunctionLikeHost(parent); ok { + if fun, ok := getFunctionLikeHost(parent); ok && fun.FunctionLikeData().FullSignature == nil { parameterTag := tag.AsJSDocParameterOrPropertyTag() if param, ok := findMatchingParameter(fun, parameterTag, jsDoc); ok { if param.Type == nil && parameterTag.TypeExpression != nil { @@ -449,7 +449,7 @@ func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) } } case ast.KindJSDocReturnTag: - if fun, ok := getFunctionLikeHost(parent); ok { + if fun, ok := getFunctionLikeHost(parent); ok && fun.FunctionLikeData().FullSignature == nil { if fun.Type() == nil && tag.AsJSDocReturnTag().TypeExpression != nil { fun.FunctionLikeData().Type = p.factory.DeepCloneReparse(tag.AsJSDocReturnTag().TypeExpression.Type()) p.finishMutatedNode(fun) diff --git a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.errors.txt b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.errors.txt deleted file mode 100644 index 45259ff67b..0000000000 --- a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.errors.txt +++ /dev/null @@ -1,33 +0,0 @@ -/a.js(2,11): error TS8040: A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag. -/a.js(8,11): error TS8040: A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag. -/a.js(15,11): error TS8040: A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag. - - -==== /a.js (3 errors) ==== - /** - * @type {(a: 1) => true} - ~~~~~~~~~~~~~~ -!!! error TS8040: A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag. - * @param {2} a - */ - export function conflictingParam(a) { return true } - - /** - * @type {(b: 3) => true} - ~~~~~~~~~~~~~~ -!!! error TS8040: A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag. - * @return {false} - */ - export function conflictingReturn(b) { return false } - - - /** - * @type {(c: 4) => true} - ~~~~~~~~~~~~~~ -!!! error TS8040: A JSDoc '@type' tag may not occur with a '@param' or '@returns' tag. - * @param {5} d - * @return {false} - */ - export function conflictingBoth(d) { return false } - - \ No newline at end of file diff --git a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.js b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.js index 488da6a2de..5c551238dd 100644 --- a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.js +++ b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.js @@ -1,44 +1,126 @@ //// [tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts] //// //// [a.js] +// @type on a function is applicable when there are no preceding @param, @return, or @template annotations +// and no @type parameter annotations. + +// @param for a parameter is applicable when there is no applicable @type annotation for the function and +// no @type annotation on the parameter. + +// @return is applicable when there is no applicable @type annotation for the function. + +// @template is applicable when there is no applicable @type annotation for the function. + /** - * @type {(a: 1) => true} - * @param {2} a + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export function conflictingParam(a) { return true } +function f1(/** @type {5}*/ a, b) { return "abc" } /** - * @type {(b: 3) => true} - * @return {false} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export function conflictingReturn(b) { return false } +function f2(a, b) { return 42 } +/** + * @param {3} a + * @type {(a: 1, b: 2) => number} + * @param {4} b + * @return {string} + */ +function f3(a, b) { return "abc" } + +/** + * @return {string} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + */ +function f4(a, b) { return "abc" } + +/** + * @type {(a: 1, b: 2) => number} + * @template T + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +function f5(a, b) { return 42 } /** - * @type {(c: 4) => true} - * @param {5} d - * @return {false} + * @template T + * @type {(a: 1, b: 2) => number} + * @template U + * @param {T} a + * @param {U} b + * @return {string} */ -export function conflictingBoth(d) { return false } +function f6(a, b) { return "abc" } +/** + * @param {1} a + * @param {2} a + */ +function f7(a) {} //// [a.d.ts] /** - * @type {(a: 1) => true} - * @param {2} a + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export declare function conflictingParam(a: 2): true; +declare function f1(/** @type {5}*/ a: 5, b: 4): string; /** - * @type {(b: 3) => true} - * @return {false} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export declare function conflictingReturn(b: 3): false; +declare function f2(a: 1, b: 2): number; /** - * @type {(c: 4) => true} - * @param {5} d - * @return {false} + * @param {3} a + * @type {(a: 1, b: 2) => number} + * @param {4} b + * @return {string} + */ +declare function f3(a: 3, b: 4): string; +/** + * @return {string} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + */ +declare function f4(a: 3, b: 4): string; +/** + * @type {(a: 1, b: 2) => number} + * @template T + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +declare function f5(a: 1, b: 2): number; +/** + * @template T + * @type {(a: 1, b: 2) => number} + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +declare function f6(a: T, b: U): string; +/** + * @param {1} a + * @param {2} a */ -export declare function conflictingBoth(d: 5): false; +declare function f7(a: 1): void; diff --git a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.symbols b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.symbols index 488ac65579..168456c74f 100644 --- a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.symbols +++ b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.symbols @@ -1,30 +1,91 @@ //// [tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts] //// === /a.js === +// @type on a function is applicable when there are no preceding @param, @return, or @template annotations +// and no @type parameter annotations. + +// @param for a parameter is applicable when there is no applicable @type annotation for the function and +// no @type annotation on the parameter. + +// @return is applicable when there is no applicable @type annotation for the function. + +// @template is applicable when there is no applicable @type annotation for the function. + /** - * @type {(a: 1) => true} - * @param {2} a + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} + */ +function f1(/** @type {5}*/ a, b) { return "abc" } +>f1 : Symbol(f1, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(a.js, 16, 12)) +>b : Symbol(b, Decl(a.js, 16, 30)) + +/** + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export function conflictingParam(a) { return true } ->conflictingParam : Symbol(conflictingParam, Decl(a.js, 0, 0)) ->a : Symbol(a, Decl(a.js, 4, 33)) +function f2(a, b) { return 42 } +>f2 : Symbol(f2, Decl(a.js, 16, 50)) +>a : Symbol(a, Decl(a.js, 24, 12)) +>b : Symbol(b, Decl(a.js, 24, 14)) /** - * @type {(b: 3) => true} - * @return {false} + * @param {3} a + * @type {(a: 1, b: 2) => number} + * @param {4} b + * @return {string} */ -export function conflictingReturn(b) { return false } ->conflictingReturn : Symbol(conflictingReturn, Decl(a.js, 4, 51)) ->b : Symbol(b, Decl(a.js, 10, 34)) +function f3(a, b) { return "abc" } +>f3 : Symbol(f3, Decl(a.js, 24, 31)) +>a : Symbol(a, Decl(a.js, 32, 12)) +>b : Symbol(b, Decl(a.js, 32, 14)) +/** + * @return {string} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + */ +function f4(a, b) { return "abc" } +>f4 : Symbol(f4, Decl(a.js, 32, 34)) +>a : Symbol(a, Decl(a.js, 40, 12)) +>b : Symbol(b, Decl(a.js, 40, 14)) + +/** + * @type {(a: 1, b: 2) => number} + * @template T + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +function f5(a, b) { return 42 } +>f5 : Symbol(f5, Decl(a.js, 40, 34)) +>a : Symbol(a, Decl(a.js, 50, 12)) +>b : Symbol(b, Decl(a.js, 50, 14)) /** - * @type {(c: 4) => true} - * @param {5} d - * @return {false} + * @template T + * @type {(a: 1, b: 2) => number} + * @template U + * @param {T} a + * @param {U} b + * @return {string} */ -export function conflictingBoth(d) { return false } ->conflictingBoth : Symbol(conflictingBoth, Decl(a.js, 10, 53)) ->d : Symbol(d, Decl(a.js, 18, 32)) +function f6(a, b) { return "abc" } +>f6 : Symbol(f6, Decl(a.js, 50, 31)) +>a : Symbol(a, Decl(a.js, 60, 12)) +>b : Symbol(b, Decl(a.js, 60, 14)) +/** + * @param {1} a + * @param {2} a + */ +function f7(a) {} +>f7 : Symbol(f7, Decl(a.js, 60, 34)) +>a : Symbol(a, Decl(a.js, 66, 12)) diff --git a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.types b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.types index 181028247a..eeeac7e45d 100644 --- a/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.types +++ b/testdata/baselines/reference/conformance/jsdocTypeParameterTagConflict.types @@ -1,33 +1,97 @@ //// [tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts] //// === /a.js === +// @type on a function is applicable when there are no preceding @param, @return, or @template annotations +// and no @type parameter annotations. + +// @param for a parameter is applicable when there is no applicable @type annotation for the function and +// no @type annotation on the parameter. + +// @return is applicable when there is no applicable @type annotation for the function. + +// @template is applicable when there is no applicable @type annotation for the function. + /** - * @type {(a: 1) => true} - * @param {2} a + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} + */ +function f1(/** @type {5}*/ a, b) { return "abc" } +>f1 : (a: 5, b: 4) => string +>a : 5 +>b : 4 +>"abc" : "abc" + +/** + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export function conflictingParam(a) { return true } ->conflictingParam : (a: 1) => true ->a : 2 ->true : true +function f2(a, b) { return 42 } +>f2 : (a: 1, b: 2) => number +>a : 1 +>b : 2 +>42 : 42 /** - * @type {(b: 3) => true} - * @return {false} + * @param {3} a + * @type {(a: 1, b: 2) => number} + * @param {4} b + * @return {string} */ -export function conflictingReturn(b) { return false } ->conflictingReturn : (b: 3) => true ->b : 3 ->false : false +function f3(a, b) { return "abc" } +>f3 : (a: 3, b: 4) => string +>a : 3 +>b : 4 +>"abc" : "abc" +/** + * @return {string} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + */ +function f4(a, b) { return "abc" } +>f4 : (a: 3, b: 4) => string +>a : 3 +>b : 4 +>"abc" : "abc" + +/** + * @type {(a: 1, b: 2) => number} + * @template T + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +function f5(a, b) { return 42 } +>f5 : (a: 1, b: 2) => number +>a : 1 +>b : 2 +>42 : 42 /** - * @type {(c: 4) => true} - * @param {5} d - * @return {false} + * @template T + * @type {(a: 1, b: 2) => number} + * @template U + * @param {T} a + * @param {U} b + * @return {string} */ -export function conflictingBoth(d) { return false } ->conflictingBoth : (c: 4) => true ->d : 5 ->false : false +function f6(a, b) { return "abc" } +>f6 : (a: T, b: U) => string +>a : T +>b : U +>"abc" : "abc" +/** + * @param {1} a + * @param {2} a + */ +function f7(a) {} +>f7 : (a: 1) => void +>a : 1 diff --git a/testdata/tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts b/testdata/tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts index ae4d73ea0e..e49959d290 100644 --- a/testdata/tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts +++ b/testdata/tests/cases/conformance/jsdoc/jsdocTypeParameterTagConflict.ts @@ -4,23 +4,71 @@ // @emitDeclarationOnly: true // @Filename: /a.js + +// @type on a function is applicable when there are no preceding @param, @return, or @template annotations +// and no @type parameter annotations. + +// @param for a parameter is applicable when there is no applicable @type annotation for the function and +// no @type annotation on the parameter. + +// @return is applicable when there is no applicable @type annotation for the function. + +// @template is applicable when there is no applicable @type annotation for the function. + /** - * @type {(a: 1) => true} - * @param {2} a + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export function conflictingParam(a) { return true } +function f1(/** @type {5}*/ a, b) { return "abc" } /** - * @type {(b: 3) => true} - * @return {false} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b + * @return {string} */ -export function conflictingReturn(b) { return false } +function f2(a, b) { return 42 } +/** + * @param {3} a + * @type {(a: 1, b: 2) => number} + * @param {4} b + * @return {string} + */ +function f3(a, b) { return "abc" } /** - * @type {(c: 4) => true} - * @param {5} d - * @return {false} + * @return {string} + * @type {(a: 1, b: 2) => number} + * @param {3} a + * @param {4} b */ -export function conflictingBoth(d) { return false } +function f4(a, b) { return "abc" } +/** + * @type {(a: 1, b: 2) => number} + * @template T + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +function f5(a, b) { return 42 } + +/** + * @template T + * @type {(a: 1, b: 2) => number} + * @template U + * @param {T} a + * @param {U} b + * @return {string} + */ +function f6(a, b) { return "abc" } + +/** + * @param {1} a + * @param {2} a + */ +function f7(a) {}