Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0760439

Browse filesBrowse files
authored
Merge pull request microsoft#16316 from Microsoft/fix14056
Better types from jsdoc type references
2 parents 4d5175b + d3d9175 commit 0760439
Copy full SHA for 0760439

4 files changed

+542-26Lines changed: 542 additions & 26 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+43-26Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6841,21 +6841,46 @@ namespace ts {
68416841
return undefined;
68426842
}
68436843

6844-
function resolveTypeReferenceName(typeReferenceName: EntityNameExpression | EntityName) {
6844+
function resolveTypeReferenceName(typeReferenceName: EntityNameExpression | EntityName, meaning: SymbolFlags) {
68456845
if (!typeReferenceName) {
68466846
return unknownSymbol;
68476847
}
68486848

6849-
return resolveEntityName(typeReferenceName, SymbolFlags.Type) || unknownSymbol;
6849+
return resolveEntityName(typeReferenceName, meaning) || unknownSymbol;
68506850
}
68516851

68526852
function getTypeReferenceType(node: TypeReferenceType, symbol: Symbol) {
68536853
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
6854-
68556854
if (symbol === unknownSymbol) {
68566855
return unknownType;
68576856
}
68586857

6858+
const type = getTypeReferenceTypeWorker(node, symbol, typeArguments);
6859+
if (type) {
6860+
return type;
6861+
}
6862+
6863+
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
6864+
// A JSDocTypeReference may have resolved to a value (as opposed to a type). If
6865+
// the symbol is a constructor function, return the inferred class type; otherwise,
6866+
// the type of this reference is just the type of the value we resolved to.
6867+
const valueType = getTypeOfSymbol(symbol);
6868+
if (valueType.symbol && !isInferredClassType(valueType)) {
6869+
const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
6870+
if (referenceType) {
6871+
return referenceType;
6872+
}
6873+
}
6874+
6875+
// Resolve the type reference as a Type for the purpose of reporting errors.
6876+
resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type);
6877+
return valueType;
6878+
}
6879+
6880+
return getTypeFromNonGenericTypeReference(node, symbol);
6881+
}
6882+
6883+
function getTypeReferenceTypeWorker(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type | undefined {
68596884
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
68606885
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
68616886
}
@@ -6864,14 +6889,9 @@ namespace ts {
68646889
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
68656890
}
68666891

6867-
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
6868-
// A JSDocTypeReference may have resolved to a value (as opposed to a type). In
6869-
// that case, the type of this reference is just the type of the value we resolved
6870-
// to.
6871-
return getTypeOfSymbol(symbol);
6892+
if (symbol.flags & SymbolFlags.Function && node.kind === SyntaxKind.JSDocTypeReference && (symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
6893+
return getInferredClassType(symbol);
68726894
}
6873-
6874-
return getTypeFromNonGenericTypeReference(node, symbol);
68756895
}
68766896

68776897
function getPrimitiveTypeFromJSDocTypeReference(node: JSDocTypeReference): Type {
@@ -6914,22 +6934,13 @@ namespace ts {
69146934
if (!links.resolvedType) {
69156935
let symbol: Symbol;
69166936
let type: Type;
6937+
let meaning = SymbolFlags.Type;
69176938
if (node.kind === SyntaxKind.JSDocTypeReference) {
6918-
type = getPrimitiveTypeFromJSDocTypeReference(<JSDocTypeReference>node);
6919-
if (!type) {
6920-
const typeReferenceName = getTypeReferenceName(node);
6921-
symbol = resolveTypeReferenceName(typeReferenceName);
6922-
type = getTypeReferenceType(node, symbol);
6923-
}
6939+
type = getPrimitiveTypeFromJSDocTypeReference(node);
6940+
meaning |= SymbolFlags.Value;
69246941
}
6925-
else {
6926-
// We only support expressions that are simple qualified names. For other expressions this produces undefined.
6927-
const typeNameOrExpression: EntityNameOrEntityNameExpression = node.kind === SyntaxKind.TypeReference
6928-
? (<TypeReferenceNode>node).typeName
6929-
: isEntityNameExpression((<ExpressionWithTypeArguments>node).expression)
6930-
? <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression
6931-
: undefined;
6932-
symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
6942+
if (!type) {
6943+
symbol = resolveTypeReferenceName(getTypeReferenceName(node), meaning);
69336944
type = getTypeReferenceType(node, symbol);
69346945
}
69356946
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
@@ -16169,6 +16180,12 @@ namespace ts {
1616916180
return links.inferredClassType;
1617016181
}
1617116182

16183+
function isInferredClassType(type: Type) {
16184+
return type.symbol
16185+
&& getObjectFlags(type) & ObjectFlags.Anonymous
16186+
&& getSymbolLinks(type.symbol).inferredClassType === type;
16187+
}
16188+
1617216189
/**
1617316190
* Syntactically and semantically checks a call or new expression.
1617416191
* @param node The call/new expression to be checked.
@@ -19392,8 +19409,8 @@ namespace ts {
1939219409

1939319410
function checkFunctionDeclaration(node: FunctionDeclaration): void {
1939419411
if (produceDiagnostics) {
19395-
checkFunctionOrMethodDeclaration(node) || checkGrammarForGenerator(node);
19396-
19412+
checkFunctionOrMethodDeclaration(node);
19413+
checkGrammarForGenerator(node);
1939719414
checkCollisionWithCapturedSuperVariable(node, node.name);
1939819415
checkCollisionWithCapturedThisVariable(node, node.name);
1939919416
checkCollisionWithCapturedNewTargetVariable(node, node.name);
Collapse file
+184Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
=== tests/cases/conformance/salsa/node.d.ts ===
2+
declare function require(id: string): any;
3+
>require : Symbol(require, Decl(node.d.ts, 0, 0))
4+
>id : Symbol(id, Decl(node.d.ts, 0, 25))
5+
6+
declare var module: any, exports: any;
7+
>module : Symbol(module, Decl(node.d.ts, 1, 11))
8+
>exports : Symbol(exports, Decl(node.d.ts, 1, 24))
9+
10+
=== tests/cases/conformance/salsa/a-ext.js ===
11+
exports.A = function () {
12+
>exports : Symbol(A, Decl(a-ext.js, 0, 0))
13+
>A : Symbol(A, Decl(a-ext.js, 0, 0))
14+
15+
this.x = 1;
16+
>x : Symbol((Anonymous function).x, Decl(a-ext.js, 0, 25))
17+
18+
};
19+
20+
=== tests/cases/conformance/salsa/a.js ===
21+
const { A } = require("./a-ext");
22+
>A : Symbol(A, Decl(a.js, 0, 7))
23+
>require : Symbol(require, Decl(node.d.ts, 0, 0))
24+
>"./a-ext" : Symbol("tests/cases/conformance/salsa/a-ext", Decl(a-ext.js, 0, 0))
25+
26+
/** @param {A} p */
27+
function a(p) { p.x; }
28+
>a : Symbol(a, Decl(a.js, 0, 33))
29+
>p : Symbol(p, Decl(a.js, 3, 11))
30+
>p.x : Symbol((Anonymous function).x, Decl(a-ext.js, 0, 25))
31+
>p : Symbol(p, Decl(a.js, 3, 11))
32+
>x : Symbol((Anonymous function).x, Decl(a-ext.js, 0, 25))
33+
34+
=== tests/cases/conformance/salsa/b-ext.js ===
35+
exports.B = class {
36+
>exports : Symbol(B, Decl(b-ext.js, 0, 0))
37+
>B : Symbol(B, Decl(b-ext.js, 0, 0))
38+
39+
constructor() {
40+
this.x = 1;
41+
>this.x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
42+
>this : Symbol((Anonymous class), Decl(b-ext.js, 0, 11))
43+
>x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
44+
}
45+
};
46+
47+
=== tests/cases/conformance/salsa/b.js ===
48+
const { B } = require("./b-ext");
49+
>B : Symbol(B, Decl(b.js, 0, 7))
50+
>require : Symbol(require, Decl(node.d.ts, 0, 0))
51+
>"./b-ext" : Symbol("tests/cases/conformance/salsa/b-ext", Decl(b-ext.js, 0, 0))
52+
53+
/** @param {B} p */
54+
function b(p) { p.x; }
55+
>b : Symbol(b, Decl(b.js, 0, 33))
56+
>p : Symbol(p, Decl(b.js, 3, 11))
57+
>p.x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
58+
>p : Symbol(p, Decl(b.js, 3, 11))
59+
>x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
60+
61+
=== tests/cases/conformance/salsa/c-ext.js ===
62+
export function C() {
63+
>C : Symbol(C, Decl(c-ext.js, 0, 0))
64+
65+
this.x = 1;
66+
>x : Symbol(C.x, Decl(c-ext.js, 0, 21))
67+
}
68+
69+
=== tests/cases/conformance/salsa/c.js ===
70+
const { C } = require("./c-ext");
71+
>C : Symbol(C, Decl(c.js, 0, 7))
72+
>require : Symbol(require, Decl(node.d.ts, 0, 0))
73+
>"./c-ext" : Symbol("tests/cases/conformance/salsa/c-ext", Decl(c-ext.js, 0, 0))
74+
75+
/** @param {C} p */
76+
function c(p) { p.x; }
77+
>c : Symbol(c, Decl(c.js, 0, 33))
78+
>p : Symbol(p, Decl(c.js, 3, 11))
79+
>p.x : Symbol(C.x, Decl(c-ext.js, 0, 21))
80+
>p : Symbol(p, Decl(c.js, 3, 11))
81+
>x : Symbol(C.x, Decl(c-ext.js, 0, 21))
82+
83+
=== tests/cases/conformance/salsa/d-ext.js ===
84+
export var D = function() {
85+
>D : Symbol(D, Decl(d-ext.js, 0, 10))
86+
87+
this.x = 1;
88+
>x : Symbol(D.x, Decl(d-ext.js, 0, 27))
89+
90+
};
91+
92+
=== tests/cases/conformance/salsa/d.js ===
93+
const { D } = require("./d-ext");
94+
>D : Symbol(D, Decl(d.js, 0, 7))
95+
>require : Symbol(require, Decl(node.d.ts, 0, 0))
96+
>"./d-ext" : Symbol("tests/cases/conformance/salsa/d-ext", Decl(d-ext.js, 0, 0))
97+
98+
/** @param {D} p */
99+
function d(p) { p.x; }
100+
>d : Symbol(d, Decl(d.js, 0, 33))
101+
>p : Symbol(p, Decl(d.js, 3, 11))
102+
>p.x : Symbol(D.x, Decl(d-ext.js, 0, 27))
103+
>p : Symbol(p, Decl(d.js, 3, 11))
104+
>x : Symbol(D.x, Decl(d-ext.js, 0, 27))
105+
106+
=== tests/cases/conformance/salsa/e-ext.js ===
107+
export class E {
108+
>E : Symbol(E, Decl(e-ext.js, 0, 0))
109+
110+
constructor() {
111+
this.x = 1;
112+
>this.x : Symbol(E.x, Decl(e-ext.js, 1, 19))
113+
>this : Symbol(E, Decl(e-ext.js, 0, 0))
114+
>x : Symbol(E.x, Decl(e-ext.js, 1, 19))
115+
}
116+
}
117+
118+
=== tests/cases/conformance/salsa/e.js ===
119+
const { E } = require("./e-ext");
120+
>E : Symbol(E, Decl(e.js, 0, 7))
121+
>require : Symbol(require, Decl(node.d.ts, 0, 0))
122+
>"./e-ext" : Symbol("tests/cases/conformance/salsa/e-ext", Decl(e-ext.js, 0, 0))
123+
124+
/** @param {E} p */
125+
function e(p) { p.x; }
126+
>e : Symbol(e, Decl(e.js, 0, 33))
127+
>p : Symbol(p, Decl(e.js, 3, 11))
128+
>p.x : Symbol(E.x, Decl(e-ext.js, 1, 19))
129+
>p : Symbol(p, Decl(e.js, 3, 11))
130+
>x : Symbol(E.x, Decl(e-ext.js, 1, 19))
131+
132+
=== tests/cases/conformance/salsa/f.js ===
133+
var F = function () {
134+
>F : Symbol(F, Decl(f.js, 0, 3))
135+
136+
this.x = 1;
137+
>x : Symbol(F.x, Decl(f.js, 0, 21))
138+
139+
};
140+
141+
/** @param {F} p */
142+
function f(p) { p.x; }
143+
>f : Symbol(f, Decl(f.js, 2, 2))
144+
>p : Symbol(p, Decl(f.js, 5, 11))
145+
>p.x : Symbol(F.x, Decl(f.js, 0, 21))
146+
>p : Symbol(p, Decl(f.js, 5, 11))
147+
>x : Symbol(F.x, Decl(f.js, 0, 21))
148+
149+
=== tests/cases/conformance/salsa/g.js ===
150+
function G() {
151+
>G : Symbol(G, Decl(g.js, 0, 0))
152+
153+
this.x = 1;
154+
>x : Symbol(G.x, Decl(g.js, 0, 14))
155+
}
156+
157+
/** @param {G} p */
158+
function g(p) { p.x; }
159+
>g : Symbol(g, Decl(g.js, 2, 1))
160+
>p : Symbol(p, Decl(g.js, 5, 11))
161+
>p.x : Symbol(G.x, Decl(g.js, 0, 14))
162+
>p : Symbol(p, Decl(g.js, 5, 11))
163+
>x : Symbol(G.x, Decl(g.js, 0, 14))
164+
165+
=== tests/cases/conformance/salsa/h.js ===
166+
class H {
167+
>H : Symbol(H, Decl(h.js, 0, 0))
168+
169+
constructor() {
170+
this.x = 1;
171+
>this.x : Symbol(H.x, Decl(h.js, 1, 19))
172+
>this : Symbol(H, Decl(h.js, 0, 0))
173+
>x : Symbol(H.x, Decl(h.js, 1, 19))
174+
}
175+
}
176+
177+
/** @param {H} p */
178+
function h(p) { p.x; }
179+
>h : Symbol(h, Decl(h.js, 4, 1))
180+
>p : Symbol(p, Decl(h.js, 7, 11))
181+
>p.x : Symbol(H.x, Decl(h.js, 1, 19))
182+
>p : Symbol(p, Decl(h.js, 7, 11))
183+
>x : Symbol(H.x, Decl(h.js, 1, 19))
184+

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.