Skip to content

Commit 8021e94

Browse files
committed
fallback-resolve namespace members on the export= symbol
1 parent 5d2d999 commit 8021e94

13 files changed

+83
-183
lines changed

internal/checker/checker.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13618,7 +13618,7 @@ func (c *Checker) getTargetOfImportEqualsDeclaration(node *ast.Node, dontResolve
1361813618
moduleReference = getExternalModuleImportEqualsDeclarationExpression(node)
1361913619
}
1362013620
immediate := c.resolveExternalModuleName(node, moduleReference, false /*ignoreErrors*/)
13621-
resolved := c.resolveExternalModuleSymbol(immediate, false /*dontResolveAlias*/)
13621+
resolved := c.resolveExternalModuleSymbol(immediate, dontResolveAlias)
1362213622
c.markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, false /*overwriteEmpty*/, nil, "")
1362313623
return resolved
1362413624
}
@@ -14545,9 +14545,24 @@ func (c *Checker) resolveEntityName(name *ast.Node, meaning ast.SymbolFlags, ign
1454514545
}
1454614546

1454714547
func (c *Checker) resolveQualifiedName(name *ast.Node, left *ast.Node, right *ast.Node, meaning ast.SymbolFlags, ignoreErrors bool, dontResolveAlias bool, location *ast.Node) *ast.Symbol {
14548-
namespace := c.resolveEntityName(left, ast.SymbolFlagsNamespace, ignoreErrors, false /*dontResolveAlias*/, location)
14548+
namespace := c.resolveEntityName(left, ast.SymbolFlagsNamespace, true /*ignoreErrors*/, false /*dontResolveAlias*/, location)
1454914549
if namespace == nil || ast.NodeIsMissing(right) {
14550-
return nil
14550+
var immediate *ast.Symbol
14551+
alias := c.resolveEntityName(left, ast.SymbolFlagsAlias, true /*ignoreErrors*/, true /*dontResolveAlias*/, location)
14552+
if alias != nil {
14553+
immediate = c.getImmediateAliasedSymbol(alias)
14554+
if immediate != nil && !core.Some(immediate.Declarations, func(d *ast.Node) bool { return d.Kind == ast.KindJSExportAssignment }) {
14555+
immediate = nil
14556+
}
14557+
}
14558+
if immediate == nil {
14559+
if !ignoreErrors {
14560+
c.resolveEntityName(left, ast.SymbolFlagsNamespace, ignoreErrors, false /*dontResolveAlias*/, location)
14561+
}
14562+
return nil
14563+
} else {
14564+
namespace = immediate
14565+
}
1455114566
}
1455214567
if namespace == c.unknownSymbol {
1455314568
return namespace
@@ -22830,9 +22845,20 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type {
2283022845
}
2283122846
next := core.OrElse(symbolFromModule, symbolFromVariable)
2283222847
if next == nil {
22833-
c.error(current, diagnostics.Namespace_0_has_no_exported_member_1, c.getFullyQualifiedName(currentNamespace, nil), scanner.DeclarationNameToString(current))
22834-
links.resolvedType = c.errorType
22835-
return links.resolvedType
22848+
var symbolFromImmediateModule *ast.Symbol
22849+
if currentNamespace == moduleSymbol {
22850+
immediateModuleSymbol := c.resolveExternalModuleSymbol(innerModuleSymbol, true /*dontResolveAlias*/)
22851+
if immediateModuleSymbol != nil && core.Some(immediateModuleSymbol.Declarations, func(d *ast.Node) bool { return d.Kind == ast.KindJSExportAssignment }) {
22852+
symbolFromImmediateModule = c.getSymbol(c.getExportsOfSymbol(immediateModuleSymbol), current.Text(), meaning)
22853+
}
22854+
}
22855+
if symbolFromImmediateModule != nil {
22856+
next = symbolFromImmediateModule
22857+
} else {
22858+
c.error(current, diagnostics.Namespace_0_has_no_exported_member_1, c.getFullyQualifiedName(currentNamespace, nil), scanner.DeclarationNameToString(current))
22859+
links.resolvedType = c.errorType
22860+
return links.resolvedType
22861+
}
2283622862
}
2283722863
c.symbolNodeLinks.Get(current).resolvedSymbol = next
2283822864
c.symbolNodeLinks.Get(current.Parent).resolvedSymbol = next

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
context.js(4,14): error TS1340: Module './timer' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./timer')'?
22
context.js(5,14): error TS1340: Module './hook' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./hook')'?
3-
context.js(6,31): error TS2694: Namespace 'Hook' has no exported member 'HookHandler'.
43
context.js(34,14): error TS2350: Only a void function can be called with the 'new' keyword.
54
hook.js(2,20): error TS1340: Module './context' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./context')'?
65

@@ -27,7 +26,7 @@ hook.js(2,20): error TS1340: Module './context' does not refer to a type, but is
2726
}
2827
module.exports = Hook;
2928

30-
==== context.js (4 errors) ====
29+
==== context.js (3 errors) ====
3130
/**
3231
* Imports
3332
*
@@ -38,8 +37,6 @@ hook.js(2,20): error TS1340: Module './context' does not refer to a type, but is
3837
~~~~~~~~~~~~~~~~
3938
!!! error TS1340: Module './hook' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./hook')'?
4039
* @typedef {import("./hook").HookHandler} HookHandler
41-
~~~~~~~~~~~
42-
!!! error TS2694: Namespace 'Hook' has no exported member 'HookHandler'.
4340
*/
4441

4542
/**

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,19 @@ module.exports = Hook;
8080
*/
8181

8282
function Context(input) {
83-
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
83+
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
8484
>input : Input
8585

8686
if (!(this instanceof Context)) {
8787
>!(this instanceof Context) : boolean
8888
>(this instanceof Context) : boolean
8989
>this instanceof Context : boolean
9090
>this : any
91-
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
91+
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
9292

9393
return new Context(input)
9494
>new Context(input) : any
95-
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
95+
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
9696
>input : Input
9797
}
9898
this.state = this.construct(input);
@@ -107,21 +107,21 @@ function Context(input) {
107107
>input : Input
108108
}
109109
Context.prototype = {
110-
>Context.prototype = { /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: any) => State; }
111-
>Context.prototype : { construct: (input: Input, handle?: any) => State; }
112-
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
113-
>prototype : { construct: (input: Input, handle?: any) => State; }
114-
>{ /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: any) => State; }
110+
>Context.prototype = { /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: HookHandler) => State; }
111+
>Context.prototype : { construct: (input: Input, handle?: HookHandler) => State; }
112+
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
113+
>prototype : { construct: (input: Input, handle?: HookHandler) => State; }
114+
>{ /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: HookHandler) => State; }
115115

116116
/**
117117
* @param {Input} input
118118
* @param {HookHandler=} handle
119119
* @returns {State}
120120
*/
121121
construct(input, handle = () => void 0) {
122-
>construct : (input: Input, handle?: any) => State
122+
>construct : (input: Input, handle?: HookHandler) => State
123123
>input : Input
124-
>handle : any
124+
>handle : HookHandler
125125
>() => void 0 : () => any
126126
>void 0 : undefined
127127
>0 : 0
@@ -131,9 +131,9 @@ Context.prototype = {
131131
}
132132
}
133133
module.exports = Context;
134-
>module.exports = Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
135-
>module.exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
136-
>module : { Context: { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }; }
137-
>exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
138-
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
134+
>module.exports = Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
135+
>module.exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
136+
>module : { Context: { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }; }
137+
>exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
138+
>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
139139

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

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

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,22 +69,22 @@ exports.C = function() {
6969
=== use.js ===
7070
/** @type {import('./mod1').Both} */
7171
var both1 = { type: 'a', x: 1 };
72-
>both1 : any
73-
>{ type: 'a', x: 1 } : { type: string; x: number; }
74-
>type : string
72+
>both1 : { type: "a"; x: 1; } | { type: "b"; y: 1; }
73+
>{ type: 'a', x: 1 } : { type: "a"; x: 1; }
74+
>type : "a"
7575
>'a' : "a"
76-
>x : number
76+
>x : 1
7777
>1 : 1
7878

7979
/** @type {import('./mod2').Both} */
8080
var both2 = both1;
8181
>both2 : Both
82-
>both1 : any
82+
>both1 : { type: "a"; x: 1; }
8383

8484
/** @type {import('./mod3').Both} */
8585
var both3 = both2;
8686
>both3 : { type: "a"; x: 1; } | { type: "b"; y: 1; }
87-
>both2 : Both
87+
>both2 : A
8888

8989

9090

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@ mod1.js(10,1): error TS2309: An export assignment cannot be used in a module wit
66
mod1.js(20,9): error TS2339: Property 'Quid' does not exist on type 'typeof import("mod1")'.
77
mod1.js(23,1): error TS2300: Duplicate identifier 'export='.
88
mod1.js(24,5): error TS2353: Object literal may only specify known properties, and 'Quack' does not exist in type '{ Baz: typeof Baz; }'.
9-
use.js(4,12): error TS2503: Cannot find namespace 'mod'.
109

1110

12-
==== use.js (1 errors) ====
11+
==== use.js (0 errors) ====
1312
var mod = require('./mod1.js');
1413
/** @type {import("./mod1.js").Baz} */
1514
var b;
1615
/** @type {mod.Baz} */
17-
~~~
18-
!!! error TS2503: Cannot find namespace 'mod'.
1916
var bb;
2017
var bbb = new mod.Baz();
2118

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var b;
1313

1414
/** @type {mod.Baz} */
1515
var bb;
16-
>bb : Baz
16+
>bb : number
1717

1818
var bbb = new mod.Baz();
1919
>bbb : Baz

testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsFunctionClassesCjsExportAssignment.errors.txt.diff

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
@@= skipped --1, +1 lines =@@
66
+context.js(4,14): error TS1340: Module './timer' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./timer')'?
77
+context.js(5,14): error TS1340: Module './hook' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./hook')'?
8-
+context.js(6,31): error TS2694: Namespace 'Hook' has no exported member 'HookHandler'.
98
+context.js(34,14): error TS2350: Only a void function can be called with the 'new' keyword.
109
+hook.js(2,20): error TS1340: Module './context' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./context')'?
1110
+
@@ -32,7 +31,7 @@
3231
+ }
3332
+ module.exports = Hook;
3433
+
35-
+==== context.js (4 errors) ====
34+
+==== context.js (3 errors) ====
3635
+ /**
3736
+ * Imports
3837
+ *
@@ -43,8 +42,6 @@
4342
+ ~~~~~~~~~~~~~~~~
4443
+!!! error TS1340: Module './hook' does not refer to a type, but is used as a type here. Did you mean 'typeof import('./hook')'?
4544
+ * @typedef {import("./hook").HookHandler} HookHandler
46-
+ ~~~~~~~~~~~
47-
+!!! error TS2694: Namespace 'Hook' has no exported member 'HookHandler'.
4845
+ */
4946
+
5047
+ /**

testdata/baselines/reference/submoduleAccepted/conformance/jsDeclarationsFunctionClassesCjsExportAssignment.types.diff

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565

6666
function Context(input) {
6767
->Context : typeof Context
68-
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
68+
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
6969
>input : Input
7070

7171
if (!(this instanceof Context)) {
@@ -75,13 +75,13 @@
7575
->this : this
7676
->Context : typeof Context
7777
+>this : any
78-
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
78+
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
7979

8080
return new Context(input)
8181
->new Context(input) : Context
8282
->Context : typeof Context
8383
+>new Context(input) : any
84-
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
84+
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
8585
>input : Input
8686
}
8787
this.state = this.construct(input);
@@ -107,11 +107,11 @@
107107
->Context : typeof Context
108108
->prototype : { construct(input: Input, handle?: HookHandler | undefined): State; }
109109
->{ /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct(input: Input, handle?: HookHandler | undefined): State; }
110-
+>Context.prototype = { /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: any) => State; }
111-
+>Context.prototype : { construct: (input: Input, handle?: any) => State; }
112-
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
113-
+>prototype : { construct: (input: Input, handle?: any) => State; }
114-
+>{ /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: any) => State; }
110+
+>Context.prototype = { /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: HookHandler) => State; }
111+
+>Context.prototype : { construct: (input: Input, handle?: HookHandler) => State; }
112+
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
113+
+>prototype : { construct: (input: Input, handle?: HookHandler) => State; }
114+
+>{ /** * @param {Input} input * @param {HookHandler=} handle * @returns {State} */ construct(input, handle = () => void 0) { return input; }} : { construct: (input: Input, handle?: HookHandler) => State; }
115115

116116
/**
117117
* @param {Input} input
@@ -120,10 +120,10 @@
120120
*/
121121
construct(input, handle = () => void 0) {
122122
->construct : (input: Input, handle?: HookHandler | undefined) => State
123-
+>construct : (input: Input, handle?: any) => State
123+
+>construct : (input: Input, handle?: HookHandler) => State
124124
>input : Input
125125
->handle : import("hook").HookHandler
126-
+>handle : any
126+
+>handle : HookHandler
127127
>() => void 0 : () => any
128128
>void 0 : undefined
129129
>0 : 0
@@ -136,9 +136,9 @@
136136
->module : { exports: { (input: Input): Context; new (input: Input): Context; prototype: { construct(input: Input, handle?: HookHandler | undefined): State; }; }; }
137137
->exports : { (input: Input): Context; new (input: Input): Context; prototype: { construct(input: Input, handle?: HookHandler | undefined): State; }; }
138138
->Context : typeof Context
139-
+>module.exports = Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
140-
+>module.exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
141-
+>module : { Context: { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }; }
142-
+>exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
143-
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: any) => State; }; }
139+
+>module.exports = Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
140+
+>module.exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
141+
+>module : { Context: { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }; }
142+
+>exports : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
143+
+>Context : { (input: Input): any; prototype: { construct: (input: Input, handle?: HookHandler) => State; }; }
144144

0 commit comments

Comments
 (0)