Skip to content

Commit 360255e

Browse files
authored
Ensure nodes have real parents, fix parent race (#970)
1 parent ca643a8 commit 360255e

26 files changed

+426
-146
lines changed

internal/ast/ast.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9643,9 +9643,10 @@ func (node *JSDocThisTag) Clone(f NodeFactoryCoercible) *Node {
96439643
// JSDocImportTag
96449644
type JSDocImportTag struct {
96459645
JSDocTagBase
9646-
ImportClause *Declaration
9647-
ModuleSpecifier *Expression
9648-
Attributes *Node
9646+
JSImportDeclaration *ImportDeclaration
9647+
ImportClause *Declaration
9648+
ModuleSpecifier *Expression
9649+
Attributes *Node
96499650
}
96509651

96519652
func (f *NodeFactory) NewJSDocImportTag(tagName *IdentifierNode, importClause *Declaration, moduleSpecifier *Node, attributes *Node, comment *NodeList) *Node {

internal/binder/binder.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,9 @@ func (b *Binder) bind(node *ast.Node) bool {
581581
if node == nil {
582582
return false
583583
}
584-
node.Parent = b.parent
584+
if node.Parent == nil || node.Parent.Flags&ast.NodeFlagsReparsed != 0 {
585+
node.Parent = b.parent
586+
}
585587
saveInStrictMode := b.inStrictMode
586588
// Even though in the AST the jsdoc @typedef node belongs to the current node,
587589
// its symbol might be in the same scope with the current node's symbol. Consider:

internal/checker/checker.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13848,6 +13848,9 @@ func (c *Checker) getTargetOfImportSpecifier(node *ast.Node, dontResolveAlias bo
1384813848
}
1384913849
}
1385013850
root := node.Parent.Parent.Parent // ImportDeclaration
13851+
if root.Kind == ast.KindJSDocImportTag {
13852+
root = root.AsJSDocImportTag().JSImportDeclaration.AsNode()
13853+
}
1385113854
if ast.IsBindingElement(node) {
1385213855
root = ast.GetRootDeclaration(node)
1385313856
}
@@ -14219,6 +14222,8 @@ func (c *Checker) getModuleSpecifierForImportOrExport(node *ast.Node) *ast.Node
1421914222

1422014223
func getModuleSpecifierFromNode(node *ast.Node) *ast.Node {
1422114224
switch node.Kind {
14225+
case ast.KindJSDocImportTag:
14226+
return node.AsJSDocImportTag().JSImportDeclaration.ModuleSpecifier
1422214227
case ast.KindImportDeclaration, ast.KindJSImportDeclaration:
1422314228
return node.AsImportDeclaration().ModuleSpecifier
1422414229
case ast.KindExportDeclaration:

internal/checker/grammarchecks.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2117,7 +2117,7 @@ func (c *Checker) checkGrammarBigIntLiteral(node *ast.BigIntLiteral) bool {
21172117
}
21182118

21192119
func (c *Checker) checkGrammarImportClause(node *ast.ImportClause) bool {
2120-
if node.IsTypeOnly && node.Name() != nil && node.NamedBindings != nil {
2120+
if node.Flags&ast.NodeFlagsJSDoc == 0 && node.IsTypeOnly && node.Name() != nil && node.NamedBindings != nil {
21212121
return c.grammarErrorOnNode(&node.Node, diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both)
21222122
}
21232123
if node.IsTypeOnly && node.NamedBindings != nil && node.NamedBindings.Kind == ast.KindNamedImports {

internal/checker/utilities.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,18 +1918,23 @@ func containsNonMissingUndefinedType(c *Checker, t *Type) bool {
19181918
}
19191919

19201920
func getAnyImportSyntax(node *ast.Node) *ast.Node {
1921+
var importNode *ast.Node
19211922
switch node.Kind {
19221923
case ast.KindImportEqualsDeclaration:
1923-
return node
1924+
importNode = node
19241925
case ast.KindImportClause:
1925-
return node.Parent
1926+
importNode = node.Parent
19261927
case ast.KindNamespaceImport:
1927-
return node.Parent.Parent
1928+
importNode = node.Parent.Parent
19281929
case ast.KindImportSpecifier:
1929-
return node.Parent.Parent.Parent
1930+
importNode = node.Parent.Parent.Parent
19301931
default:
19311932
return nil
19321933
}
1934+
if importNode.Kind == ast.KindJSDocImportTag {
1935+
return importNode.AsJSDocImportTag().JSImportDeclaration.AsNode()
1936+
}
1937+
return importNode
19331938
}
19341939

19351940
// A reserved member name consists of the byte 0xFE (which is an invalid UTF-8 encoding) followed by one or more

internal/parser/reparser.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func (p *Parser) reparseTags(parent *ast.Node, jsDoc []*ast.Node) {
9898
importDeclaration.Loc = core.NewTextRange(tag.Pos(), tag.End())
9999
importDeclaration.Flags = p.contextFlags | ast.NodeFlagsReparsed
100100
p.reparseList = append(p.reparseList, importDeclaration)
101+
importTag.JSImportDeclaration = importDeclaration.AsImportDeclaration()
101102
// !!! @overload and other unattached tags (@callback et al) support goes here
102103
}
103104
if !isLast {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
index.js(2,28): error TS2304: Cannot find name 'B'.
2+
index.js(2,42): error TS2304: Cannot find name 'A'.
3+
index.js(2,48): error TS2304: Cannot find name 'B'.
4+
index.js(2,67): error TS2304: Cannot find name 'B'.
5+
6+
7+
==== index.js (4 errors) ====
8+
/**
9+
* @typedef {{ [K in keyof B]: { fn: (a: A, b: B) => void; thing: B[K]; } }} Funcs
10+
~
11+
!!! error TS2304: Cannot find name 'B'.
12+
~
13+
!!! error TS2304: Cannot find name 'A'.
14+
~
15+
!!! error TS2304: Cannot find name 'B'.
16+
~
17+
!!! error TS2304: Cannot find name 'B'.
18+
* @template A
19+
* @template {Record<string, unknown>} B
20+
*/
21+
22+
/**
23+
* @template A
24+
* @template {Record<string, unknown>} B
25+
* @param {Funcs<A, B>} fns
26+
* @returns {[A, B]}
27+
*/
28+
function foo(fns) {
29+
return /** @type {any} */ (null);
30+
}
31+
32+
const result = foo({
33+
bar: {
34+
fn:
35+
/** @param {string} a */
36+
(a) => {},
37+
thing: "asd",
38+
},
39+
});

testdata/baselines/reference/submodule/compiler/contravariantOnlyInferenceFromAnnotatedFunctionJs.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@
1414
* @returns {[A, B]}
1515
*/
1616
function foo(fns) {
17-
>foo : <A, B extends Record<string, unknown>>(fns: Funcs<A, B>) => [A, B]
18-
>fns : Funcs<A, B>
17+
>foo : <A, B extends Record<string, unknown>>(fns: { [x: string]: { fn: (a: A, b: B) => void; thing: B; }; }) => [A, B]
18+
>fns : { [x: string]: { fn: (a: A, b: B) => void; thing: B; }; }
1919

2020
return /** @type {any} */ (null);
2121
>(null) : any
2222
>null : any
2323
}
2424

2525
const result = foo({
26-
>result : [string, { bar: string; }]
27-
>foo({ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },}) : [string, { bar: string; }]
28-
>foo : <A, B extends Record<string, unknown>>(fns: Funcs<A, B>) => [A, B]
26+
>result : [unknown, Record<string, unknown>]
27+
>foo({ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },}) : [unknown, Record<string, unknown>]
28+
>foo : <A, B extends Record<string, unknown>>(fns: { [x: string]: { fn: (a: A, b: B) => void; thing: B; }; }) => [A, B]
2929
>{ bar: { fn: /** @param {string} a */ (a) => {}, thing: "asd", },} : { bar: { fn: (a: string) => void; thing: string; }; }
3030

3131
bar: {

testdata/baselines/reference/submodule/conformance/importTag16.errors.txt

Lines changed: 0 additions & 18 deletions
This file was deleted.

testdata/baselines/reference/submodule/conformance/jsDeclarationsFunctionClassesCjsExportAssignment.types

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,22 @@ module.exports = Timer;
3030
* @param {HookHandler} handle
3131
*/
3232
function Hook(handle) {
33-
>Hook : (handle: HookHandler) => void
34-
>handle : HookHandler
33+
>Hook : (handle: (arg: any) => void) => void
34+
>handle : (arg: any) => void
3535

3636
this.handle = handle;
37-
>this.handle = handle : HookHandler
37+
>this.handle = handle : (arg: any) => void
3838
>this.handle : any
3939
>this : any
4040
>handle : any
41-
>handle : HookHandler
41+
>handle : (arg: any) => void
4242
}
4343
module.exports = Hook;
44-
>module.exports = Hook : (handle: HookHandler) => void
45-
>module.exports : (handle: HookHandler) => void
46-
>module : { Hook(handle: HookHandler): void; }
47-
>exports : (handle: HookHandler) => void
48-
>Hook : (handle: HookHandler) => void
44+
>module.exports = Hook : (handle: (arg: any) => void) => void
45+
>module.exports : (handle: (arg: any) => void) => void
46+
>module : { Hook(handle: (arg: any) => void): void; }
47+
>exports : (handle: (arg: any) => void) => void
48+
>Hook : (handle: (arg: any) => void) => void
4949

5050
=== context.js ===
5151
/**

0 commit comments

Comments
 (0)