Skip to content

Commit e8e80d2

Browse files
author
Andy
authored
Don't crash on property access with type (microsoft#25170)
* Don't crash on property access with type * Move test
1 parent b3a6428 commit e8e80d2

File tree

6 files changed

+62
-9
lines changed

6 files changed

+62
-9
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4650,15 +4650,15 @@ namespace ts {
46504650
let jsDocType: Type | undefined;
46514651
for (const declaration of symbol.declarations) {
46524652
let declarationInConstructor = false;
4653-
const expression = declaration.kind === SyntaxKind.BinaryExpression ? <BinaryExpression>declaration :
4654-
declaration.kind === SyntaxKind.PropertyAccessExpression ? cast(declaration.parent, isBinaryExpression) :
4653+
const expression = isBinaryExpression(declaration) ? declaration :
4654+
isPropertyAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration :
46554655
undefined;
46564656

46574657
if (!expression) {
46584658
return errorType;
46594659
}
46604660

4661-
const special = getSpecialPropertyAssignmentKind(expression);
4661+
const special = isPropertyAccessExpression(expression) ? getSpecialPropertyAccessKind(expression) : getSpecialPropertyAssignmentKind(expression);
46624662
if (special === SpecialPropertyAssignmentKind.ThisProperty) {
46634663
const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false);
46644664
// Properties defined in a constructor (or base constructor, or javascript constructor function) don't get undefined added.
@@ -4687,7 +4687,7 @@ namespace ts {
46874687
errorNextVariableOrPropertyDeclarationMustHaveSameType(jsDocType, declaration, declarationType);
46884688
}
46894689
}
4690-
else if (!jsDocType) {
4690+
else if (!jsDocType && isBinaryExpression(expression)) {
46914691
// If we don't have an explicit JSDoc type, get the type from the expression.
46924692
let type = getWidenedLiteralType(checkExpressionCached(expression.right));
46934693

src/compiler/utilities.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,6 +1887,14 @@ namespace ts {
18871887
return SpecialPropertyAssignmentKind.None;
18881888
}
18891889
const lhs = expr.left;
1890+
if (isEntityNameExpression(lhs.expression) && lhs.name.escapedText === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) {
1891+
// F.prototype = { ... }
1892+
return SpecialPropertyAssignmentKind.Prototype;
1893+
}
1894+
return getSpecialPropertyAccessKind(lhs);
1895+
}
1896+
1897+
export function getSpecialPropertyAccessKind(lhs: PropertyAccessExpression): SpecialPropertyAssignmentKind {
18901898
if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
18911899
return SpecialPropertyAssignmentKind.ThisProperty;
18921900
}
@@ -1895,11 +1903,7 @@ namespace ts {
18951903
return SpecialPropertyAssignmentKind.ModuleExports;
18961904
}
18971905
else if (isEntityNameExpression(lhs.expression)) {
1898-
if (lhs.name.escapedText === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) {
1899-
// F.prototype = { ... }
1900-
return SpecialPropertyAssignmentKind.Prototype;
1901-
}
1902-
else if (isPrototypeAccess(lhs.expression)) {
1906+
if (isPrototypeAccess(lhs.expression)) {
19031907
// F.G....prototype.x = expr
19041908
return SpecialPropertyAssignmentKind.PrototypeProperty;
19051909
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6262,6 +6262,7 @@ declare namespace ts {
62626262
function isExportsIdentifier(node: Node): boolean;
62636263
function isModuleExportsPropertyAccessExpression(node: Node): boolean;
62646264
function getSpecialPropertyAssignmentKind(expr: BinaryExpression): SpecialPropertyAssignmentKind;
6265+
function getSpecialPropertyAccessKind(lhs: PropertyAccessExpression): SpecialPropertyAssignmentKind;
62656266
function getInitializerOfBinaryExpression(expr: BinaryExpression): Expression;
62666267
function isPrototypePropertyAssignment(node: Node): boolean;
62676268
function isSpecialPropertyDeclaration(expr: PropertyAccessExpression): boolean;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== /a.js ===
2+
function C() { this.x = false; };
3+
>C : Symbol(C, Decl(a.js, 0, 0))
4+
>x : Symbol(C.x, Decl(a.js, 0, 14), Decl(a.js, 0, 33))
5+
6+
/** @type {number} */
7+
C.prototype.x;
8+
>C.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
9+
>C : Symbol(C, Decl(a.js, 0, 0))
10+
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
11+
12+
new C().x;
13+
>new C().x : Symbol(C.x, Decl(a.js, 0, 14), Decl(a.js, 0, 33))
14+
>C : Symbol(C, Decl(a.js, 0, 0))
15+
>x : Symbol(C.x, Decl(a.js, 0, 14), Decl(a.js, 0, 33))
16+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== /a.js ===
2+
function C() { this.x = false; };
3+
>C : typeof C
4+
>this.x = false : false
5+
>this.x : any
6+
>this : any
7+
>x : any
8+
>false : false
9+
10+
/** @type {number} */
11+
C.prototype.x;
12+
>C.prototype.x : any
13+
>C.prototype : any
14+
>C : typeof C
15+
>prototype : any
16+
>x : any
17+
18+
new C().x;
19+
>new C().x : number
20+
>new C() : C
21+
>C : typeof C
22+
>x : number
23+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
5+
// @Filename: /a.js
6+
function C() { this.x = false; };
7+
/** @type {number} */
8+
C.prototype.x;
9+
new C().x;

0 commit comments

Comments
 (0)