Skip to content

Commit 6da2cdd

Browse files
authored
Merge pull request #63 from bloomberg/helper-parameter-count
produce an error if private field helpers are not up to date
2 parents 3b62d3c + 93a7ca3 commit 6da2cdd

17 files changed

+357
-33
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26791,12 +26791,18 @@ namespace ts {
2679126791
const parentSymbol = getNodeLinks(left).resolvedSymbol;
2679226792
const assignmentKind = getAssignmentTargetKind(node);
2679326793
const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType);
26794-
if (isPrivateIdentifier(right)) {
26795-
checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldGet);
26796-
}
2679726794
const isAnyLike = isTypeAny(apparentType) || apparentType === silentNeverType;
2679826795
let prop: Symbol | undefined;
2679926796
if (isPrivateIdentifier(right)) {
26797+
if (languageVersion < ScriptTarget.ESNext) {
26798+
if (assignmentKind !== AssignmentKind.None) {
26799+
checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldSet);
26800+
}
26801+
if (assignmentKind !== AssignmentKind.Definite) {
26802+
checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldGet);
26803+
}
26804+
}
26805+
2680026806
const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right);
2680126807
if (assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration)) {
2680226808
grammarErrorOnNode(right, Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, idText(right));
@@ -26817,7 +26823,7 @@ namespace ts {
2681726823
}
2681826824
else {
2681926825
const isSetonlyAccessor = prop && prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
26820-
if (isSetonlyAccessor && !isAssignmentTarget(node)) {
26826+
if (isSetonlyAccessor && assignmentKind !== AssignmentKind.Definite) {
2682126827
error(node, Diagnostics.Private_accessor_was_defined_without_a_getter);
2682226828
}
2682326829
}
@@ -39906,6 +39912,16 @@ namespace ts {
3990639912
if (!symbol) {
3990739913
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name);
3990839914
}
39915+
else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) {
39916+
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) {
39917+
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 4);
39918+
}
39919+
}
39920+
else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) {
39921+
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) {
39922+
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 5);
39923+
}
39924+
}
3990939925
}
3991039926
}
3991139927
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3300,6 +3300,10 @@
33003300
"category": "Error",
33013301
"code": 2806
33023302
},
3303+
"This syntax requires an imported helper named '{1}' with {2} parameters, which is not compatible with the one in '{0}'. Consider upgrading your version of '{0}'.": {
3304+
"category": "Error",
3305+
"code": 2807
3306+
},
33033307

33043308
"Import declaration '{0}' is using private name '{1}'.": {
33053309
"category": "Error",
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/conformance/classes/members/privateNames/main.ts(3,12): error TS2807: This syntax requires an imported helper named '__classPrivateFieldSet' with 5 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
2+
tests/cases/conformance/classes/members/privateNames/main.ts(4,25): error TS2807: This syntax requires an imported helper named '__classPrivateFieldGet' with 4 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
3+
4+
5+
==== tests/cases/conformance/classes/members/privateNames/main.ts (2 errors) ====
6+
export class C {
7+
#a = 1;
8+
#b() { this.#c = 42; }
9+
~~~~~~~
10+
!!! error TS2807: This syntax requires an imported helper named '__classPrivateFieldSet' with 5 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
11+
set #c(v: number) { this.#a += v; }
12+
~~~~~~~
13+
!!! error TS2807: This syntax requires an imported helper named '__classPrivateFieldGet' with 4 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
14+
}
15+
16+
==== tests/cases/conformance/classes/members/privateNames/tslib.d.ts (0 errors) ====
17+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
18+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
19+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
20+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [tests/cases/conformance/classes/members/privateNames/privateNameEmitHelpers.ts] ////
2+
3+
//// [main.ts]
4+
export class C {
5+
#a = 1;
6+
#b() { this.#c = 42; }
7+
set #c(v: number) { this.#a += v; }
8+
}
9+
10+
//// [tslib.d.ts]
11+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
12+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
13+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
14+
15+
16+
//// [main.js]
17+
var _C_instances, _C_a, _C_b, _C_c_set;
18+
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
19+
export class C {
20+
constructor() {
21+
_C_instances.add(this);
22+
_C_a.set(this, 1);
23+
}
24+
}
25+
_C_a = new WeakMap(), _C_instances = new WeakSet(), _C_b = function _C_b() { __classPrivateFieldSet(this, _C_instances, 42, "a", _C_c_set); }, _C_c_set = function _C_c_set(v) { __classPrivateFieldSet(this, _C_a, __classPrivateFieldGet(this, _C_a, "f") + v, "f"); };
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
=== tests/cases/conformance/classes/members/privateNames/main.ts ===
2+
export class C {
3+
>C : Symbol(C, Decl(main.ts, 0, 0))
4+
5+
#a = 1;
6+
>#a : Symbol(C.#a, Decl(main.ts, 0, 16))
7+
8+
#b() { this.#c = 42; }
9+
>#b : Symbol(C.#b, Decl(main.ts, 1, 11))
10+
>this.#c : Symbol(C.#c, Decl(main.ts, 2, 26))
11+
>this : Symbol(C, Decl(main.ts, 0, 0))
12+
13+
set #c(v: number) { this.#a += v; }
14+
>#c : Symbol(C.#c, Decl(main.ts, 2, 26))
15+
>v : Symbol(v, Decl(main.ts, 3, 11))
16+
>this.#a : Symbol(C.#a, Decl(main.ts, 0, 16))
17+
>this : Symbol(C, Decl(main.ts, 0, 0))
18+
>v : Symbol(v, Decl(main.ts, 3, 11))
19+
}
20+
21+
=== tests/cases/conformance/classes/members/privateNames/tslib.d.ts ===
22+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
23+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
24+
>__classPrivateFieldGet : Symbol(__classPrivateFieldGet, Decl(tslib.d.ts, --, --))
25+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
26+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
27+
>receiver : Symbol(receiver, Decl(tslib.d.ts, --, --))
28+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
29+
>state : Symbol(state, Decl(tslib.d.ts, --, --))
30+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
31+
32+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
33+
>__classPrivateFieldSet : Symbol(__classPrivateFieldSet, Decl(tslib.d.ts, --, --))
34+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
35+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
36+
>receiver : Symbol(receiver, Decl(tslib.d.ts, --, --))
37+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
38+
>state : Symbol(state, Decl(tslib.d.ts, --, --))
39+
>value : Symbol(value, Decl(tslib.d.ts, --, --))
40+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
41+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
42+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/classes/members/privateNames/main.ts ===
2+
export class C {
3+
>C : C
4+
5+
#a = 1;
6+
>#a : number
7+
>1 : 1
8+
9+
#b() { this.#c = 42; }
10+
>#b : () => void
11+
>this.#c = 42 : 42
12+
>this.#c : number
13+
>this : this
14+
>42 : 42
15+
16+
set #c(v: number) { this.#a += v; }
17+
>#c : number
18+
>v : number
19+
>this.#a += v : number
20+
>this.#a : number
21+
>this : this
22+
>v : number
23+
}
24+
25+
=== tests/cases/conformance/classes/members/privateNames/tslib.d.ts ===
26+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
27+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
28+
>__classPrivateFieldGet : <T extends object, V>(receiver: T, state: any) => V
29+
>receiver : T
30+
>state : any
31+
32+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
33+
>__classPrivateFieldSet : <T extends object, V>(receiver: T, state: any, value: V) => V
34+
>receiver : T
35+
>state : any
36+
>value : V
37+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/conformance/classes/members/privateNames/main.ts(3,19): error TS2807: This syntax requires an imported helper named '__classPrivateFieldSet' with 5 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
2+
tests/cases/conformance/classes/members/privateNames/main.ts(4,30): error TS2807: This syntax requires an imported helper named '__classPrivateFieldGet' with 4 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
3+
4+
5+
==== tests/cases/conformance/classes/members/privateNames/main.ts (2 errors) ====
6+
export class S {
7+
static #a = 1;
8+
static #b() { this.#a = 42; }
9+
~~~~~~~
10+
!!! error TS2807: This syntax requires an imported helper named '__classPrivateFieldSet' with 5 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
11+
static get #c() { return S.#b(); }
12+
~~~~
13+
!!! error TS2807: This syntax requires an imported helper named '__classPrivateFieldGet' with 4 parameters, which is not compatible with the one in 'tslib'. Consider upgrading your version of 'tslib'.
14+
}
15+
16+
==== tests/cases/conformance/classes/members/privateNames/tslib.d.ts (0 errors) ====
17+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
18+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
19+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
20+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/conformance/classes/members/privateNames/privateNameStaticEmitHelpers.ts] ////
2+
3+
//// [main.ts]
4+
export class S {
5+
static #a = 1;
6+
static #b() { this.#a = 42; }
7+
static get #c() { return S.#b(); }
8+
}
9+
10+
//// [tslib.d.ts]
11+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
12+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
13+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
14+
15+
16+
//// [main.js]
17+
var _a, _S_a, _S_b, _S_c_get;
18+
import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
19+
export class S {
20+
}
21+
_a = S, _S_b = function _S_b() { __classPrivateFieldSet(this, _a, 42, "f", _S_a); }, _S_c_get = function _S_c_get() { return __classPrivateFieldGet(S, _a, "m", _S_b).call(S); };
22+
_S_a = { value: 1 };
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/conformance/classes/members/privateNames/main.ts ===
2+
export class S {
3+
>S : Symbol(S, Decl(main.ts, 0, 0))
4+
5+
static #a = 1;
6+
>#a : Symbol(S.#a, Decl(main.ts, 0, 16))
7+
8+
static #b() { this.#a = 42; }
9+
>#b : Symbol(S.#b, Decl(main.ts, 1, 18))
10+
>this.#a : Symbol(S.#a, Decl(main.ts, 0, 16))
11+
>this : Symbol(S, Decl(main.ts, 0, 0))
12+
13+
static get #c() { return S.#b(); }
14+
>#c : Symbol(S.#c, Decl(main.ts, 2, 33))
15+
>S.#b : Symbol(S.#b, Decl(main.ts, 1, 18))
16+
>S : Symbol(S, Decl(main.ts, 0, 0))
17+
}
18+
19+
=== tests/cases/conformance/classes/members/privateNames/tslib.d.ts ===
20+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
21+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
22+
>__classPrivateFieldGet : Symbol(__classPrivateFieldGet, Decl(tslib.d.ts, --, --))
23+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
24+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
25+
>receiver : Symbol(receiver, Decl(tslib.d.ts, --, --))
26+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
27+
>state : Symbol(state, Decl(tslib.d.ts, --, --))
28+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
29+
30+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
31+
>__classPrivateFieldSet : Symbol(__classPrivateFieldSet, Decl(tslib.d.ts, --, --))
32+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
33+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
34+
>receiver : Symbol(receiver, Decl(tslib.d.ts, --, --))
35+
>T : Symbol(T, Decl(tslib.d.ts, --, --))
36+
>state : Symbol(state, Decl(tslib.d.ts, --, --))
37+
>value : Symbol(value, Decl(tslib.d.ts, --, --))
38+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
39+
>V : Symbol(V, Decl(tslib.d.ts, --, --))
40+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
=== tests/cases/conformance/classes/members/privateNames/main.ts ===
2+
export class S {
3+
>S : S
4+
5+
static #a = 1;
6+
>#a : number
7+
>1 : 1
8+
9+
static #b() { this.#a = 42; }
10+
>#b : () => void
11+
>this.#a = 42 : 42
12+
>this.#a : number
13+
>this : typeof S
14+
>42 : 42
15+
16+
static get #c() { return S.#b(); }
17+
>#c : void
18+
>S.#b() : void
19+
>S.#b : () => void
20+
>S : typeof S
21+
}
22+
23+
=== tests/cases/conformance/classes/members/privateNames/tslib.d.ts ===
24+
// these are pre-TS4.3 versions of emit helpers, which only supported private instance fields
25+
export declare function __classPrivateFieldGet<T extends object, V>(receiver: T, state: any): V;
26+
>__classPrivateFieldGet : <T extends object, V>(receiver: T, state: any) => V
27+
>receiver : T
28+
>state : any
29+
30+
export declare function __classPrivateFieldSet<T extends object, V>(receiver: T, state: any, value: V): V;
31+
>__classPrivateFieldSet : <T extends object, V>(receiver: T, state: any, value: V) => V
32+
>receiver : T
33+
>state : any
34+
>value : V
35+

0 commit comments

Comments
 (0)