Skip to content

Commit 55b48d4

Browse files
committed
Done except for cleanup and fix 1 bug
1 parent 8974fb5 commit 55b48d4

10 files changed

+357
-52
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11964,7 +11964,7 @@ namespace ts {
1196411964
if (prop) {
1196511965
if (accessExpression) {
1196611966
markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword);
11967-
if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) {
11967+
if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) {
1196811968
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop));
1196911969
return undefined;
1197011970
}
@@ -23046,11 +23046,9 @@ namespace ts {
2304623046
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
2304723047
getNodeLinks(node).resolvedSymbol = prop;
2304823048
checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
23049-
if (assignmentKind) {
23050-
if (isReferenceToReadonlyEntity(<Expression>node, prop) || isReferenceThroughNamespaceImport(<Expression>node)) {
23051-
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
23052-
return errorType;
23053-
}
23049+
if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
23050+
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
23051+
return errorType;
2305423052
}
2305523053
propType = getConstraintForLocation(getTypeOfSymbol(prop), node);
2305623054
}
@@ -26332,7 +26330,11 @@ namespace ts {
2633226330
);
2633326331
}
2633426332

26335-
function isReferenceToReadonlyEntity(expr: Expression, symbol: Symbol): boolean {
26333+
function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) {
26334+
if (assignmentKind === AssignmentKind.None) {
26335+
// no assigment means it doesn't matter whether the entity is readonly
26336+
return false;
26337+
}
2633626338
if (isReadonlySymbol(symbol)) {
2633726339
// Allow assignments to readonly properties within constructors of the same class declaration.
2633826340
if (symbol.flags & SymbolFlags.Property &&
@@ -26351,15 +26353,20 @@ namespace ts {
2635126353
// If func.parent is a class and symbol is a (readonly) property of that class, or
2635226354
// if func is a constructor and symbol is a (readonly) parameter property declared in it,
2635326355
// then symbol is writeable here.
26354-
return !symbol.valueDeclaration || !(ctor.parent === symbol.valueDeclaration.parent || ctor === symbol.valueDeclaration.parent);
26356+
if (symbol.valueDeclaration) {
26357+
const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent;
26358+
const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent;
26359+
const isLocalThisPropertyAssignment = symbol.parent && symbol.parent.valueDeclaration === ctor.parent; // TODO: Make sure that symbol.parent is a function and class
26360+
const isLocalThisPropertyAssignmentConstructorFunction = symbol.parent && symbol.parent.valueDeclaration === ctor; // TODO: Make sure that symbol.parent is a function and class
26361+
const isLocalProperty = isLocalPropertyDeclaration || isLocalParameterProperty || isLocalThisPropertyAssignment || isLocalThisPropertyAssignmentConstructorFunction ;
26362+
return !isLocalProperty;
26363+
}
26364+
return false;
2635526365
}
2635626366
return true;
2635726367
}
26358-
return false;
26359-
}
26360-
26361-
function isReferenceThroughNamespaceImport(expr: Expression): boolean {
2636226368
if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
26369+
// references through namespace import should be readonly
2636326370
const node = skipParentheses((expr as AccessExpression).expression);
2636426371
if (node.kind === SyntaxKind.Identifier) {
2636526372
const symbol = getNodeLinks(node).resolvedSymbol!;

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

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -386,23 +386,24 @@ declare namespace ts {
386386
JSDocPublicTag = 308,
387387
JSDocPrivateTag = 309,
388388
JSDocProtectedTag = 310,
389-
JSDocCallbackTag = 311,
390-
JSDocEnumTag = 312,
391-
JSDocParameterTag = 313,
392-
JSDocReturnTag = 314,
393-
JSDocThisTag = 315,
394-
JSDocTypeTag = 316,
395-
JSDocTemplateTag = 317,
396-
JSDocTypedefTag = 318,
397-
JSDocPropertyTag = 319,
398-
SyntaxList = 320,
399-
NotEmittedStatement = 321,
400-
PartiallyEmittedExpression = 322,
401-
CommaListExpression = 323,
402-
MergeDeclarationMarker = 324,
403-
EndOfDeclarationMarker = 325,
404-
SyntheticReferenceExpression = 326,
405-
Count = 327,
389+
JSDocReadonlyTag = 311,
390+
JSDocCallbackTag = 312,
391+
JSDocEnumTag = 313,
392+
JSDocParameterTag = 314,
393+
JSDocReturnTag = 315,
394+
JSDocThisTag = 316,
395+
JSDocTypeTag = 317,
396+
JSDocTemplateTag = 318,
397+
JSDocTypedefTag = 319,
398+
JSDocPropertyTag = 320,
399+
SyntaxList = 321,
400+
NotEmittedStatement = 322,
401+
PartiallyEmittedExpression = 323,
402+
CommaListExpression = 324,
403+
MergeDeclarationMarker = 325,
404+
EndOfDeclarationMarker = 326,
405+
SyntheticReferenceExpression = 327,
406+
Count = 328,
406407
FirstAssignment = 62,
407408
LastAssignment = 74,
408409
FirstCompoundAssignment = 63,
@@ -431,9 +432,9 @@ declare namespace ts {
431432
LastStatement = 240,
432433
FirstNode = 152,
433434
FirstJSDocNode = 292,
434-
LastJSDocNode = 319,
435+
LastJSDocNode = 320,
435436
FirstJSDocTagNode = 304,
436-
LastJSDocTagNode = 319,
437+
LastJSDocTagNode = 320,
437438
}
438439
export enum NodeFlags {
439440
None = 0,
@@ -1632,6 +1633,9 @@ declare namespace ts {
16321633
export interface JSDocProtectedTag extends JSDocTag {
16331634
kind: SyntaxKind.JSDocProtectedTag;
16341635
}
1636+
export interface JSDocReadonlyTag extends JSDocTag {
1637+
kind: SyntaxKind.JSDocReadonlyTag;
1638+
}
16351639
export interface JSDocEnumTag extends JSDocTag, Declaration {
16361640
parent: JSDoc;
16371641
kind: SyntaxKind.JSDocEnumTag;
@@ -3472,6 +3476,8 @@ declare namespace ts {
34723476
function getJSDocPrivateTag(node: Node): JSDocPrivateTag | undefined;
34733477
/** Gets the JSDoc protected tag for the node if present */
34743478
function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined;
3479+
/** Gets the JSDoc protected tag for the node if present */
3480+
function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined;
34753481
/** Gets the JSDoc enum tag for the node if present */
34763482
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
34773483
/** Gets the JSDoc this tag for the node if present */
@@ -3679,6 +3685,7 @@ declare namespace ts {
36793685
function isJSDocPublicTag(node: Node): node is JSDocPublicTag;
36803686
function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag;
36813687
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
3688+
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
36823689
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
36833690
function isJSDocThisTag(node: Node): node is JSDocThisTag;
36843691
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;

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

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -386,23 +386,24 @@ declare namespace ts {
386386
JSDocPublicTag = 308,
387387
JSDocPrivateTag = 309,
388388
JSDocProtectedTag = 310,
389-
JSDocCallbackTag = 311,
390-
JSDocEnumTag = 312,
391-
JSDocParameterTag = 313,
392-
JSDocReturnTag = 314,
393-
JSDocThisTag = 315,
394-
JSDocTypeTag = 316,
395-
JSDocTemplateTag = 317,
396-
JSDocTypedefTag = 318,
397-
JSDocPropertyTag = 319,
398-
SyntaxList = 320,
399-
NotEmittedStatement = 321,
400-
PartiallyEmittedExpression = 322,
401-
CommaListExpression = 323,
402-
MergeDeclarationMarker = 324,
403-
EndOfDeclarationMarker = 325,
404-
SyntheticReferenceExpression = 326,
405-
Count = 327,
389+
JSDocReadonlyTag = 311,
390+
JSDocCallbackTag = 312,
391+
JSDocEnumTag = 313,
392+
JSDocParameterTag = 314,
393+
JSDocReturnTag = 315,
394+
JSDocThisTag = 316,
395+
JSDocTypeTag = 317,
396+
JSDocTemplateTag = 318,
397+
JSDocTypedefTag = 319,
398+
JSDocPropertyTag = 320,
399+
SyntaxList = 321,
400+
NotEmittedStatement = 322,
401+
PartiallyEmittedExpression = 323,
402+
CommaListExpression = 324,
403+
MergeDeclarationMarker = 325,
404+
EndOfDeclarationMarker = 326,
405+
SyntheticReferenceExpression = 327,
406+
Count = 328,
406407
FirstAssignment = 62,
407408
LastAssignment = 74,
408409
FirstCompoundAssignment = 63,
@@ -431,9 +432,9 @@ declare namespace ts {
431432
LastStatement = 240,
432433
FirstNode = 152,
433434
FirstJSDocNode = 292,
434-
LastJSDocNode = 319,
435+
LastJSDocNode = 320,
435436
FirstJSDocTagNode = 304,
436-
LastJSDocTagNode = 319,
437+
LastJSDocTagNode = 320,
437438
}
438439
export enum NodeFlags {
439440
None = 0,
@@ -1632,6 +1633,9 @@ declare namespace ts {
16321633
export interface JSDocProtectedTag extends JSDocTag {
16331634
kind: SyntaxKind.JSDocProtectedTag;
16341635
}
1636+
export interface JSDocReadonlyTag extends JSDocTag {
1637+
kind: SyntaxKind.JSDocReadonlyTag;
1638+
}
16351639
export interface JSDocEnumTag extends JSDocTag, Declaration {
16361640
parent: JSDoc;
16371641
kind: SyntaxKind.JSDocEnumTag;
@@ -3472,6 +3476,8 @@ declare namespace ts {
34723476
function getJSDocPrivateTag(node: Node): JSDocPrivateTag | undefined;
34733477
/** Gets the JSDoc protected tag for the node if present */
34743478
function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined;
3479+
/** Gets the JSDoc protected tag for the node if present */
3480+
function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined;
34753481
/** Gets the JSDoc enum tag for the node if present */
34763482
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
34773483
/** Gets the JSDoc this tag for the node if present */
@@ -3679,6 +3685,7 @@ declare namespace ts {
36793685
function isJSDocPublicTag(node: Node): node is JSDocPublicTag;
36803686
function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag;
36813687
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
3688+
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
36823689
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
36833690
function isJSDocThisTag(node: Node): node is JSDocThisTag;
36843691
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;

tests/baselines/reference/jsDeclarationsClasses.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ export class E<T, U> {
477477
* @type {string}
478478
* @readonly
479479
*/
480-
static staticReadonlyField: string;
480+
static readonly staticReadonlyField: string;
481481
static staticInitializedField: number;
482482
/**
483483
* @param {string} _p
@@ -508,7 +508,7 @@ export class E<T, U> {
508508
* @type {T & U}
509509
* @readonly
510510
*/
511-
readonlyField: T & U;
511+
readonly readonlyField: T & U;
512512
initializedField: number;
513513
/**
514514
* @param {U} _p
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
tests/cases/conformance/jsdoc/jsdocReadonly.js(23,3): error TS2540: Cannot assign to 'y' because it is a read-only property.
2+
3+
4+
==== tests/cases/conformance/jsdoc/jsdocReadonly.js (1 errors) ====
5+
class LOL {
6+
/**
7+
* @readonly
8+
* @private
9+
* @type {number}
10+
* Order rules do not apply to JSDoc
11+
*/
12+
x = 1
13+
/** @readonly */
14+
y = 2
15+
/** @readonly Definitely not here */
16+
static z = 3
17+
/** @readonly This is OK too */
18+
constructor() {
19+
/** ok */
20+
this.y = 2
21+
/** @readonly ok */
22+
this.ka = 2
23+
}
24+
}
25+
26+
var l = new LOL()
27+
l.y = 12
28+
~
29+
!!! error TS2540: Cannot assign to 'y' because it is a read-only property.
30+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/conformance/jsdoc/jsdocReadonly.js ===
2+
class LOL {
3+
>LOL : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
4+
5+
/**
6+
* @readonly
7+
* @private
8+
* @type {number}
9+
* Order rules do not apply to JSDoc
10+
*/
11+
x = 1
12+
>x : Symbol(LOL.x, Decl(jsdocReadonly.js, 0, 11))
13+
14+
/** @readonly */
15+
y = 2
16+
>y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
17+
18+
/** @readonly Definitely not here */
19+
static z = 3
20+
>z : Symbol(LOL.z, Decl(jsdocReadonly.js, 9, 9))
21+
22+
/** @readonly This is OK too */
23+
constructor() {
24+
/** ok */
25+
this.y = 2
26+
>this.y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
27+
>this : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
28+
>y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
29+
30+
/** @readonly ok */
31+
this.ka = 2
32+
>this.ka : Symbol(LOL.ka, Decl(jsdocReadonly.js, 15, 18))
33+
>this : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
34+
>ka : Symbol(LOL.ka, Decl(jsdocReadonly.js, 15, 18))
35+
}
36+
}
37+
38+
var l = new LOL()
39+
>l : Symbol(l, Decl(jsdocReadonly.js, 21, 3), Decl(jsdocReadonly.js, 21, 17))
40+
>LOL : Symbol(LOL, Decl(jsdocReadonly.js, 0, 0))
41+
42+
l.y = 12
43+
>l.y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
44+
>l : Symbol(l, Decl(jsdocReadonly.js, 21, 3), Decl(jsdocReadonly.js, 21, 17))
45+
>y : Symbol(LOL.y, Decl(jsdocReadonly.js, 7, 9))
46+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=== tests/cases/conformance/jsdoc/jsdocReadonly.js ===
2+
class LOL {
3+
>LOL : LOL
4+
5+
/**
6+
* @readonly
7+
* @private
8+
* @type {number}
9+
* Order rules do not apply to JSDoc
10+
*/
11+
x = 1
12+
>x : number
13+
>1 : 1
14+
15+
/** @readonly */
16+
y = 2
17+
>y : 2
18+
>2 : 2
19+
20+
/** @readonly Definitely not here */
21+
static z = 3
22+
>z : 3
23+
>3 : 3
24+
25+
/** @readonly This is OK too */
26+
constructor() {
27+
/** ok */
28+
this.y = 2
29+
>this.y = 2 : 2
30+
>this.y : 2
31+
>this : this
32+
>y : 2
33+
>2 : 2
34+
35+
/** @readonly ok */
36+
this.ka = 2
37+
>this.ka = 2 : 2
38+
>this.ka : number
39+
>this : this
40+
>ka : number
41+
>2 : 2
42+
}
43+
}
44+
45+
var l = new LOL()
46+
>l : LOL
47+
>new LOL() : LOL
48+
>LOL : typeof LOL
49+
50+
l.y = 12
51+
>l.y = 12 : 12
52+
>l.y : any
53+
>l : LOL
54+
>y : any
55+
>12 : 12
56+

0 commit comments

Comments
 (0)