diff --git a/internal/checker/checker.go b/internal/checker/checker.go index fe177224e93..482d097f2bb 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10703,8 +10703,7 @@ func (c *Checker) checkSatisfiesExpression(node *ast.Node) *Type { if c.isErrorType(targetType) { return targetType } - errorNode := core.IfElse(typeNode.Flags&ast.NodeFlagsReparsed != 0, typeNode, node) - c.checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, errorNode, node.Expression(), diagnostics.Type_0_does_not_satisfy_the_expected_type_1, nil) + c.checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, node, node.Expression(), diagnostics.Type_0_does_not_satisfy_the_expected_type_1, nil) return exprType } diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index a52e10b1396..c5df2ec53f5 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -2514,6 +2514,38 @@ func getErrorRangeForArrowFunction(sourceFile *ast.SourceFile, node *ast.Node) c return core.NewTextRange(pos, node.End()) } +func findOriginatingJSDocSatisfiesTag(sourceFile *ast.SourceFile, node *ast.Node) *ast.Node { + targetType := node.AsSatisfiesExpression().Type + if targetType.Flags&ast.NodeFlagsReparsed == 0 { + return nil + } + for current := node.Parent; current != nil; current = current.Parent { + if current.Flags&ast.NodeFlagsHasJSDoc == 0 { + continue + } + var firstSatisfiesTag *ast.Node + for _, jsDoc := range current.EagerJSDoc(sourceFile) { + if tags := jsDoc.AsJSDoc().Tags; tags != nil { + for _, tag := range tags.Nodes { + if !ast.IsJSDocSatisfiesTag(tag) { + continue + } + if firstSatisfiesTag == nil { + firstSatisfiesTag = tag + } + if typeExpr := tag.AsJSDocSatisfiesTag().TypeExpression; typeExpr != nil { + if t := typeExpr.Type(); t != nil && t.Loc == targetType.Loc { + return tag + } + } + } + } + } + return firstSatisfiesTag + } + return nil +} + func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextRange { errorNode := node switch node.Kind { @@ -2552,6 +2584,10 @@ func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextR pos := SkipTrivia(sourceFile.Text(), node.Pos()) return GetRangeOfTokenAtPosition(sourceFile, pos) case ast.KindSatisfiesExpression: + if jsDocSatisfiesTag := findOriginatingJSDocSatisfiesTag(sourceFile, node); jsDocSatisfiesTag != nil { + pos := SkipTrivia(sourceFile.Text(), jsDocSatisfiesTag.TagName().Pos()) + return GetRangeOfTokenAtPosition(sourceFile, pos) + } pos := SkipTrivia(sourceFile.Text(), node.AsSatisfiesExpression().Expression.End()) return GetRangeOfTokenAtPosition(sourceFile, pos) case ast.KindConstructor: @@ -2565,10 +2601,6 @@ func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextR scanner.Scan() } return core.NewTextRange(start, scanner.TokenEnd()) - // !!! - // case KindJSDocSatisfiesTag: - // pos := scanner.SkipTrivia(sourceFile.Text(), node.tagName.pos) - // return scanner.GetRangeOfTokenAtPosition(sourceFile, pos) } if errorNode == nil { // If we don't have a better node, then just set the error on the first token of diff --git a/testdata/baselines/reference/compiler/jsdocSatisfiesTagWithParamTag.errors.txt b/testdata/baselines/reference/compiler/jsdocSatisfiesTagWithParamTag.errors.txt index fc08b92f658..db5c0fab15a 100644 --- a/testdata/baselines/reference/compiler/jsdocSatisfiesTagWithParamTag.errors.txt +++ b/testdata/baselines/reference/compiler/jsdocSatisfiesTagWithParamTag.errors.txt @@ -1,4 +1,4 @@ -/a.js(9,16): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. +/a.js(9,5): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. Types of parameters 'b' and 'args' are incompatible. Type 'number' is not assignable to type 'string'. @@ -13,7 +13,7 @@ /** * @satisfies {(a: string, ...args: number[]) => void} - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~ !!! error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. !!! error TS1360: Types of parameters 'b' and 'args' are incompatible. !!! error TS1360: Type 'number' is not assignable to type 'string'. diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt index d9dbd2c6e51..f6d39be52d4 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt @@ -1,5 +1,5 @@ /a.js(21,44): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'. -/a.js(22,28): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. +/a.js(22,17): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. /a.js(31,49): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T4'. @@ -28,7 +28,7 @@ ~ !!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'. const t3 = /** @satisfies {T1} */ ({}); - ~~ + ~~~~~~~~~ !!! error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. !!! related TS2728 /a.js:3:23: 'a' is declared here. diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt.diff b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt.diff index 30a35d0db40..444ccf3f1dc 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.errors.txt.diff @@ -4,19 +4,17 @@ /a.js(21,44): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'. -/a.js(22,17): error TS1360: Type '{}' does not satisfy the expected type 'T1'. - Property 'a' is missing in type '{}' but required in type 'T1'. -+/a.js(22,28): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. ++/a.js(22,17): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. /a.js(31,49): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T4'. -@@= skipped -28, +27 lines =@@ - ~ +@@= skipped -29, +28 lines =@@ !!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'. const t3 = /** @satisfies {T1} */ ({}); -- ~~~~~~~~~ + ~~~~~~~~~ -!!! error TS1360: Type '{}' does not satisfy the expected type 'T1'. -!!! error TS1360: Property 'a' is missing in type '{}' but required in type 'T1'. -!!! related TS2728 /a.js:3:4: 'a' is declared here. -+ ~~ +!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. +!!! related TS2728 /a.js:3:23: 'a' is declared here. diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt index 23f2335a68d..13365202edc 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt @@ -1,7 +1,7 @@ /a.js(24,20): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'. -/a.js(27,16): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. +/a.js(27,5): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. /a.js(44,25): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T2'. -/a.js(51,17): error TS1360: Type 'number' does not satisfy the expected type 'string'. +/a.js(51,6): error TS1360: Type 'number' does not satisfy the expected type 'string'. ==== /a.js (4 errors) ==== @@ -34,7 +34,7 @@ /** * @satisfies {T1} - ~~ + ~~~~~~~~~ !!! error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. !!! related TS2728 /a.js:3:23: 'a' is declared here. */ @@ -63,6 +63,6 @@ const t7 = { a: "a" }; /** @satisfies {string} */ const t8 = (1); - ~~~~~~ + ~~~~~~~~~ !!! error TS1360: Type 'number' does not satisfy the expected type 'string'. \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt.diff b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt.diff index 9fb50fa561e..a10a0c758ae 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag12.errors.txt.diff @@ -2,15 +2,12 @@ +++ new.checkJsdocSatisfiesTag12.errors.txt @@= skipped -0, +0 lines =@@ /a.js(24,20): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T1'. -+/a.js(27,16): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. ++/a.js(27,5): error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. /a.js(44,25): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'T2'. --/a.js(51,6): error TS1360: Type 'number' does not satisfy the expected type 'string'. -- -- + /a.js(51,6): error TS1360: Type 'number' does not satisfy the expected type 'string'. + + -==== /a.js (3 errors) ==== -+/a.js(51,17): error TS1360: Type 'number' does not satisfy the expected type 'string'. -+ -+ +==== /a.js (4 errors) ==== /** * @typedef {Object} T1 @@ -19,17 +16,9 @@ /** * @satisfies {T1} -+ ~~ ++ ~~~~~~~~~ +!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'T1'. +!!! related TS2728 /a.js:3:23: 'a' is declared here. */ const t3 = {}; - -@@= skipped -26, +29 lines =@@ - const t7 = { a: "a" }; - - /** @satisfies {string} */ const t8 = (1); -- ~~~~~~~~~ -+ ~~~~~~ - !!! error TS1360: Type 'number' does not satisfy the expected type 'string'. \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt index eee6000eb69..40ceaa21a4e 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt @@ -1,5 +1,5 @@ /a.js(9,20): error TS2322: Type 'number' is not assignable to type 'string'. -/a.js(28,16): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. +/a.js(28,5): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. Types of parameters 'b' and 'args' are incompatible. Type 'number' is not assignable to type 'string'. /a.js(42,21): error TS7006: Parameter 'uuid' implicitly has an 'any' type. @@ -36,7 +36,7 @@ /** * @satisfies {(a: string, ...args: number[]) => void} - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~ !!! error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. !!! error TS1360: Types of parameters 'b' and 'args' are incompatible. !!! error TS1360: Type 'number' is not assignable to type 'string'. diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt.diff b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt.diff deleted file mode 100644 index 3fca8047981..00000000000 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag15.errors.txt.diff +++ /dev/null @@ -1,18 +0,0 @@ ---- old.checkJsdocSatisfiesTag15.errors.txt -+++ new.checkJsdocSatisfiesTag15.errors.txt -@@= skipped -0, +0 lines =@@ - /a.js(9,20): error TS2322: Type 'number' is not assignable to type 'string'. --/a.js(28,5): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. -+/a.js(28,16): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. - Types of parameters 'b' and 'args' are incompatible. - Type 'number' is not assignable to type 'string'. - /a.js(42,21): error TS7006: Parameter 'uuid' implicitly has an 'any' type. -@@= skipped -35, +35 lines =@@ - - /** - * @satisfies {(a: string, ...args: number[]) => void} -- ~~~~~~~~~ -+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - !!! error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'. - !!! error TS1360: Types of parameters 'b' and 'args' are incompatible. - !!! error TS1360: Type 'number' is not assignable to type 'string'. \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt index c5445a8150d..4f08a1f03ef 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt @@ -1,4 +1,4 @@ -/a.js(5,32): error TS2741: Property 'a' is missing in type '{}' but required in type 'Foo'. +/a.js(5,21): error TS2741: Property 'a' is missing in type '{}' but required in type 'Foo'. ==== /a.js (1 errors) ==== @@ -7,7 +7,7 @@ * @property {number} a */ export default /** @satisfies {Foo} */ ({}); - ~~~ + ~~~~~~~~~ !!! error TS2741: Property 'a' is missing in type '{}' but required in type 'Foo'. !!! related TS2728 /a.js:3:23: 'a' is declared here. diff --git a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt.diff b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt.diff index 3d8e1e84b39..acedf400751 100644 --- a/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt.diff +++ b/testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag4.errors.txt.diff @@ -3,19 +3,17 @@ @@= skipped -0, +0 lines =@@ -/a.js(5,21): error TS1360: Type '{}' does not satisfy the expected type 'Foo'. - Property 'a' is missing in type '{}' but required in type 'Foo'. -+/a.js(5,32): error TS2741: Property 'a' is missing in type '{}' but required in type 'Foo'. ++/a.js(5,21): error TS2741: Property 'a' is missing in type '{}' but required in type 'Foo'. ==== /a.js (1 errors) ==== -@@= skipped -7, +6 lines =@@ - * @property {number} a +@@= skipped -8, +7 lines =@@ */ export default /** @satisfies {Foo} */ ({}); -- ~~~~~~~~~ + ~~~~~~~~~ -!!! error TS1360: Type '{}' does not satisfy the expected type 'Foo'. -!!! error TS1360: Property 'a' is missing in type '{}' but required in type 'Foo'. -!!! related TS2728 /a.js:3:4: 'a' is declared here. -+ ~~~ +!!! error TS2741: Property 'a' is missing in type '{}' but required in type 'Foo'. +!!! related TS2728 /a.js:3:23: 'a' is declared here.