Skip to content

Commit 6e09169

Browse files
committed
Merge branch 'master' into referencesPrototypeSourceFile
2 parents a469fd8 + 4bddf55 commit 6e09169

13 files changed

+364
-100
lines changed

src/compiler/checker.ts

Lines changed: 61 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,6 +2560,22 @@ namespace ts {
25602560
return initializer || decl;
25612561
}
25622562

2563+
/**
2564+
* Get the real symbol of a declaration with an expando initializer.
2565+
*
2566+
* Normally, declarations have an associated symbol, but when a declaration has an expando
2567+
* initializer, the expando's symbol is the one that has all the members merged into it.
2568+
*/
2569+
function getExpandoSymbol(symbol: Symbol): Symbol | undefined {
2570+
const decl = symbol.valueDeclaration;
2571+
if (!decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias) {
2572+
return undefined;
2573+
}
2574+
const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) : getAssignedExpandoInitializer(decl);
2575+
return init && getSymbolOfNode(init) || undefined;
2576+
}
2577+
2578+
25632579
function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression, ignoreErrors?: boolean): Symbol | undefined {
25642580
return resolveExternalModuleNameWorker(location, moduleReferenceExpression, ignoreErrors ? undefined : Diagnostics.Cannot_find_module_0);
25652581
}
@@ -9195,10 +9211,13 @@ namespace ts {
91959211
if (symbol === unknownSymbol) {
91969212
return errorType;
91979213
}
9214+
symbol = getExpandoSymbol(symbol) || symbol;
91989215

9199-
const type = getTypeReferenceTypeWorker(node, symbol, typeArguments);
9200-
if (type) {
9201-
return type;
9216+
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
9217+
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
9218+
}
9219+
if (symbol.flags & SymbolFlags.TypeAlias) {
9220+
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
92029221
}
92039222

92049223
// Get type from reference to named type that cannot be generic (enum or type parameter)
@@ -9209,62 +9228,34 @@ namespace ts {
92099228
errorType;
92109229
}
92119230

9212-
if (!(symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node))) {
9213-
return errorType;
9214-
}
9215-
9216-
const jsdocType = getJSDocTypeReference(node, symbol, typeArguments);
9217-
if (jsdocType) {
9218-
return jsdocType;
9231+
if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) {
9232+
const jsdocType = getTypeFromJSAlias(node, symbol);
9233+
if (jsdocType) {
9234+
return jsdocType;
9235+
}
9236+
else {
9237+
// Resolve the type reference as a Type for the purpose of reporting errors.
9238+
resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type);
9239+
return getTypeOfSymbol(symbol);
9240+
}
92199241
}
92209242

9221-
// Resolve the type reference as a Type for the purpose of reporting errors.
9222-
resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type);
9223-
return getTypeOfSymbol(symbol);
9243+
return errorType;
92249244
}
92259245

92269246
/**
9227-
* A jsdoc TypeReference may have resolved to a value (as opposed to a type). If
9228-
* the symbol is a constructor function, return the inferred class type; otherwise,
9229-
* the type of this reference is just the type of the value we resolved to.
9247+
* A JSdoc TypeReference may be to a value imported from commonjs.
9248+
* These should really be aliases, but this special-case code fakes alias resolution
9249+
* by producing a type from a value.
92309250
*/
9231-
function getJSDocTypeReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined {
9232-
// In the case of an assignment of a function expression (binary expressions, variable declarations, etc.), we will get the
9233-
// correct instance type for the symbol on the LHS by finding the type for RHS. For example if we want to get the type of the symbol `foo`:
9234-
// var foo = function() {}
9235-
// We will find the static type of the assigned anonymous function.
9236-
const staticType = getTypeOfSymbol(symbol);
9237-
const instanceType =
9238-
staticType.symbol &&
9239-
staticType.symbol !== symbol && // Make sure this is an assignment like expression by checking that symbol -> type -> symbol doesn't roundtrips.
9240-
getTypeReferenceTypeWorker(node, staticType.symbol, typeArguments); // Get the instance type of the RHS symbol.
9241-
if (instanceType) {
9242-
return getSymbolLinks(symbol).resolvedJSDocType = instanceType;
9243-
}
9244-
}
9245-
9246-
function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined {
9247-
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
9248-
if (symbol.valueDeclaration && symbol.valueDeclaration.parent && isBinaryExpression(symbol.valueDeclaration.parent)) {
9249-
const jsdocType = getJSDocTypeReference(node, symbol, typeArguments);
9250-
if (jsdocType) {
9251-
return jsdocType;
9252-
}
9253-
}
9254-
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
9255-
}
9256-
9257-
if (symbol.flags & SymbolFlags.TypeAlias) {
9258-
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
9259-
}
9260-
9261-
if (symbol.flags & SymbolFlags.Function &&
9262-
isJSDocTypeReference(node) &&
9263-
isJSConstructor(symbol.valueDeclaration)) {
9264-
const resolved = resolveStructuredTypeMembers(<ObjectType>getTypeOfSymbol(symbol));
9265-
if (resolved.callSignatures.length === 1) {
9266-
return getReturnTypeOfSignature(resolved.callSignatures[0]);
9267-
}
9251+
function getTypeFromJSAlias(node: NodeWithTypeArguments, symbol: Symbol): Type | undefined {
9252+
const valueType = getTypeOfSymbol(symbol);
9253+
const typeType =
9254+
valueType.symbol &&
9255+
valueType.symbol !== symbol && // Make sure this is a commonjs export by checking that symbol -> type -> symbol doesn't roundtrip.
9256+
getTypeReferenceType(node, valueType.symbol);
9257+
if (typeType) {
9258+
return getSymbolLinks(symbol).resolvedJSDocType = typeType;
92689259
}
92699260
}
92709261

@@ -22879,24 +22870,29 @@ namespace ts {
2287922870

2288022871
// If the symbol of the node has members, treat it like a constructor.
2288122872
const symbol = getSymbolOfNode(func);
22882-
return !!symbol && symbol.members !== undefined;
22873+
return !!symbol && hasEntries(symbol.members);
2288322874
}
2288422875
return false;
2288522876
}
2288622877

2288722878
function mergeJSSymbols(target: Symbol, source: Symbol | undefined) {
2288822879
if (source && (hasEntries(source.exports) || hasEntries(source.members))) {
22889-
target = cloneSymbol(target);
22890-
if (hasEntries(source.exports)) {
22891-
target.exports = target.exports || createSymbolTable();
22892-
mergeSymbolTable(target.exports, source.exports);
22893-
}
22894-
if (hasEntries(source.members)) {
22895-
target.members = target.members || createSymbolTable();
22896-
mergeSymbolTable(target.members, source.members);
22897-
}
22898-
target.flags |= source.flags & SymbolFlags.Class;
22899-
return target as TransientSymbol;
22880+
const links = getSymbolLinks(source);
22881+
if (!links.inferredClassSymbol || !links.inferredClassSymbol.has("" + getSymbolId(target))) {
22882+
const inferred = isTransientSymbol(target) ? target : cloneSymbol(target) as TransientSymbol;
22883+
inferred.exports = inferred.exports || createSymbolTable();
22884+
inferred.members = inferred.members || createSymbolTable();
22885+
inferred.flags |= source.flags & SymbolFlags.Class;
22886+
if (hasEntries(source.exports)) {
22887+
mergeSymbolTable(inferred.exports, source.exports);
22888+
}
22889+
if (hasEntries(source.members)) {
22890+
mergeSymbolTable(inferred.members, source.members);
22891+
}
22892+
(links.inferredClassSymbol || (links.inferredClassSymbol = createMap<TransientSymbol>())).set("" + getSymbolId(inferred), inferred);
22893+
return inferred;
22894+
}
22895+
return links.inferredClassSymbol.get("" + getSymbolId(target));
2290022896
}
2290122897
}
2290222898

src/compiler/types.ts

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,30 +3772,31 @@ namespace ts {
37723772

37733773
/* @internal */
37743774
export interface SymbolLinks {
3775-
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
3776-
target?: Symbol; // Resolved (non-alias) target of an alias
3777-
type?: Type; // Type of value symbol
3778-
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
3779-
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
3780-
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
3781-
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
3782-
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
3783-
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
3784-
mapper?: TypeMapper; // Type mapper for instantiation alias
3785-
referenced?: boolean; // True if alias symbol has been referenced as a value
3786-
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
3787-
leftSpread?: Symbol; // Left source for synthetic spread property
3788-
rightSpread?: Symbol; // Right source for synthetic spread property
3789-
syntheticOrigin?: Symbol; // For a property on a mapped or spread type, points back to the original property
3790-
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
3791-
resolvedExports?: SymbolTable; // Resolved exports of module or combined early- and late-bound static members of a class.
3792-
resolvedMembers?: SymbolTable; // Combined early- and late-bound members of a symbol
3793-
exportsChecked?: boolean; // True if exports of external module have been checked
3794-
typeParametersChecked?: boolean; // True if type parameters of merged class and interface declarations have been checked.
3775+
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
3776+
target?: Symbol; // Resolved (non-alias) target of an alias
3777+
type?: Type; // Type of value symbol
3778+
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
3779+
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
3780+
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
3781+
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
3782+
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
3783+
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
3784+
inferredClassSymbol?: Map<TransientSymbol>; // Symbol of an inferred ES5 constructor function
3785+
mapper?: TypeMapper; // Type mapper for instantiation alias
3786+
referenced?: boolean; // True if alias symbol has been referenced as a value
3787+
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
3788+
leftSpread?: Symbol; // Left source for synthetic spread property
3789+
rightSpread?: Symbol; // Right source for synthetic spread property
3790+
syntheticOrigin?: Symbol; // For a property on a mapped or spread type, points back to the original property
3791+
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
3792+
resolvedExports?: SymbolTable; // Resolved exports of module or combined early- and late-bound static members of a class.
3793+
resolvedMembers?: SymbolTable; // Combined early- and late-bound members of a symbol
3794+
exportsChecked?: boolean; // True if exports of external module have been checked
3795+
typeParametersChecked?: boolean; // True if type parameters of merged class and interface declarations have been checked.
37953796
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
3796-
bindingElement?: BindingElement; // Binding element associated with property symbol
3797-
exportsSomeValue?: boolean; // True if module exports some value (not just types)
3798-
enumKind?: EnumKind; // Enum declaration classification
3797+
bindingElement?: BindingElement; // Binding element associated with property symbol
3798+
exportsSomeValue?: boolean; // True if module exports some value (not just types)
3799+
enumKind?: EnumKind; // Enum declaration classification
37993800
originatingImport?: ImportDeclaration | ImportCall; // Import declaration which produced the symbol, present if the symbol is marked as uncallable but had call signatures in `resolveESModuleSymbol`
38003801
lateSymbol?: Symbol; // Late-bound symbol for a computed property
38013802
specifierCache?: Map<string>; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings

tests/baselines/reference/chainedPrototypeAssignment.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ tests/cases/conformance/salsa/use.js(6,5): error TS2345: Argument of type '"not
1919
declare var exports: any;
2020
==== tests/cases/conformance/salsa/mod.js (0 errors) ====
2121
/// <reference path='./types.d.ts'/>
22-
var A = function() {
22+
var A = function A() {
2323
this.a = 1
2424
}
25-
var B = function() {
25+
var B = function B() {
2626
this.b = 2
2727
}
2828
exports.A = A

tests/baselines/reference/chainedPrototypeAssignment.symbols

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,19 @@ declare var exports: any;
3737

3838
=== tests/cases/conformance/salsa/mod.js ===
3939
/// <reference path='./types.d.ts'/>
40-
var A = function() {
40+
var A = function A() {
4141
>A : Symbol(A, Decl(mod.js, 1, 3), Decl(mod.js, 8, 13))
42+
>A : Symbol(A, Decl(mod.js, 1, 7))
4243

4344
this.a = 1
44-
>a : Symbol(A.a, Decl(mod.js, 1, 20))
45+
>a : Symbol(A.a, Decl(mod.js, 1, 22))
4546
}
46-
var B = function() {
47+
var B = function B() {
4748
>B : Symbol(B, Decl(mod.js, 4, 3), Decl(mod.js, 9, 13))
49+
>B : Symbol(B, Decl(mod.js, 4, 7))
4850

4951
this.b = 2
50-
>b : Symbol(B.b, Decl(mod.js, 4, 20))
52+
>b : Symbol(B.b, Decl(mod.js, 4, 22))
5153
}
5254
exports.A = A
5355
>exports.A : Symbol(A, Decl(mod.js, 6, 1))

tests/baselines/reference/chainedPrototypeAssignment.types

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ declare var exports: any;
4444

4545
=== tests/cases/conformance/salsa/mod.js ===
4646
/// <reference path='./types.d.ts'/>
47-
var A = function() {
47+
var A = function A() {
48+
>A : typeof A
49+
>function A() { this.a = 1} : typeof A
4850
>A : typeof A
49-
>function() { this.a = 1} : typeof A
5051

5152
this.a = 1
5253
>this.a = 1 : 1
@@ -55,9 +56,10 @@ var A = function() {
5556
>a : any
5657
>1 : 1
5758
}
58-
var B = function() {
59+
var B = function B() {
60+
>B : typeof B
61+
>function B() { this.b = 2} : typeof B
5962
>B : typeof B
60-
>function() { this.b = 2} : typeof B
6163

6264
this.b = 2
6365
>this.b = 2 : 2
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/conformance/salsa/jsdocConstructorFunctionTypeReference.js ===
2+
var Validator = function VFunc() {
3+
>Validator : Symbol(Validator, Decl(jsdocConstructorFunctionTypeReference.js, 0, 3))
4+
>VFunc : Symbol(VFunc, Decl(jsdocConstructorFunctionTypeReference.js, 0, 15))
5+
6+
this.flags = "gim"
7+
>flags : Symbol(VFunc.flags, Decl(jsdocConstructorFunctionTypeReference.js, 0, 34))
8+
9+
};
10+
11+
Validator.prototype.num = 12
12+
>Validator.prototype : Symbol(Validator.num, Decl(jsdocConstructorFunctionTypeReference.js, 2, 2))
13+
>Validator : Symbol(Validator, Decl(jsdocConstructorFunctionTypeReference.js, 0, 3))
14+
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
15+
>num : Symbol(Validator.num, Decl(jsdocConstructorFunctionTypeReference.js, 2, 2))
16+
17+
/**
18+
* @param {Validator} state
19+
*/
20+
var validateRegExpFlags = function(state) {
21+
>validateRegExpFlags : Symbol(validateRegExpFlags, Decl(jsdocConstructorFunctionTypeReference.js, 9, 3))
22+
>state : Symbol(state, Decl(jsdocConstructorFunctionTypeReference.js, 9, 35))
23+
24+
return state.flags
25+
>state.flags : Symbol(VFunc.flags, Decl(jsdocConstructorFunctionTypeReference.js, 0, 34))
26+
>state : Symbol(state, Decl(jsdocConstructorFunctionTypeReference.js, 9, 35))
27+
>flags : Symbol(VFunc.flags, Decl(jsdocConstructorFunctionTypeReference.js, 0, 34))
28+
29+
};
30+
31+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/conformance/salsa/jsdocConstructorFunctionTypeReference.js ===
2+
var Validator = function VFunc() {
3+
>Validator : typeof VFunc
4+
>function VFunc() { this.flags = "gim"} : typeof VFunc
5+
>VFunc : typeof VFunc
6+
7+
this.flags = "gim"
8+
>this.flags = "gim" : "gim"
9+
>this.flags : any
10+
>this : any
11+
>flags : any
12+
>"gim" : "gim"
13+
14+
};
15+
16+
Validator.prototype.num = 12
17+
>Validator.prototype.num = 12 : 12
18+
>Validator.prototype.num : any
19+
>Validator.prototype : any
20+
>Validator : typeof VFunc
21+
>prototype : any
22+
>num : any
23+
>12 : 12
24+
25+
/**
26+
* @param {Validator} state
27+
*/
28+
var validateRegExpFlags = function(state) {
29+
>validateRegExpFlags : (state: VFunc) => string
30+
>function(state) { return state.flags} : (state: VFunc) => string
31+
>state : VFunc
32+
33+
return state.flags
34+
>state.flags : string
35+
>state : VFunc
36+
>flags : string
37+
38+
};
39+
40+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
tests/cases/conformance/salsa/other.js(5,5): error TS2339: Property 'wat' does not exist on type 'One'.
2+
tests/cases/conformance/salsa/other.js(10,5): error TS2339: Property 'wat' does not exist on type 'Two'.
3+
4+
5+
==== tests/cases/conformance/salsa/prototypePropertyAssignmentMergeAcrossFiles2.js (0 errors) ====
6+
var Ns = {}
7+
Ns.One = function() {};
8+
Ns.Two = function() {};
9+
10+
Ns.One.prototype = {
11+
ok() {},
12+
};
13+
Ns.Two.prototype = {
14+
}
15+
16+
==== tests/cases/conformance/salsa/other.js (2 errors) ====
17+
/**
18+
* @type {Ns.One}
19+
*/
20+
var one;
21+
one.wat;
22+
~~~
23+
!!! error TS2339: Property 'wat' does not exist on type 'One'.
24+
/**
25+
* @type {Ns.Two}
26+
*/
27+
var two;
28+
two.wat;
29+
~~~
30+
!!! error TS2339: Property 'wat' does not exist on type 'Two'.
31+

0 commit comments

Comments
 (0)