Skip to content

Commit 35d25ff

Browse files
authored
Merge pull request microsoft#24645 from Kingwl/this-type-accessibility
allow access protected member in this parameter context
2 parents 3cd6db7 + ee310a4 commit 35d25ff

File tree

6 files changed

+622
-4
lines changed

6 files changed

+622
-4
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17122,20 +17122,28 @@ namespace ts {
1712217122

1712317123
// Find the first enclosing class that has the declaring classes of the protected constituents
1712417124
// of the property as base classes
17125-
const enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => {
17125+
let enclosingClass = forEachEnclosingClass(node, enclosingDeclaration => {
1712617126
const enclosingClass = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingDeclaration)!);
1712717127
return isClassDerivedFromDeclaringClasses(enclosingClass, prop) ? enclosingClass : undefined;
1712817128
});
1712917129
// A protected property is accessible if the property is within the declaring class or classes derived from it
1713017130
if (!enclosingClass) {
17131-
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || type));
17132-
return false;
17131+
// allow PropertyAccessibility if context is in function with this parameter
17132+
// static member access is disallow
17133+
let thisParameter: ParameterDeclaration | undefined;
17134+
if (flags & ModifierFlags.Static || !(thisParameter = getThisParameterFromNodeContext(node)) || !thisParameter.type) {
17135+
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(getDeclaringClass(prop) || type));
17136+
return false;
17137+
}
17138+
17139+
const thisType = getTypeFromTypeNode(thisParameter.type);
17140+
enclosingClass = ((thisType.flags & TypeFlags.TypeParameter) ? getConstraintFromTypeParameter(<TypeParameter>thisType) : thisType) as InterfaceType;
1713317141
}
1713417142
// No further restrictions for static properties
1713517143
if (flags & ModifierFlags.Static) {
1713617144
return true;
1713717145
}
17138-
if (type.flags & TypeFlags.TypeParameter) {
17146+
if (type.flags & TypeFlags.TypeParameter) {
1713917147
// get the original type -- represented as the type constraint of the 'this' type
1714017148
type = (type as TypeParameter).isThisType ? getConstraintOfTypeParameter(<TypeParameter>type)! : getBaseConstraintOfType(<TypeParameter>type)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined
1714117149
}
@@ -17146,6 +17154,11 @@ namespace ts {
1714617154
return true;
1714717155
}
1714817156

17157+
function getThisParameterFromNodeContext (node: Node) {
17158+
const thisContainer = getThisContainer(node, /* includeArrowFunctions */ false);
17159+
return thisContainer && isFunctionLike(thisContainer) ? getThisParameter(thisContainer) : undefined;
17160+
}
17161+
1714917162
function symbolHasNonMethodDeclaration(symbol: Symbol) {
1715017163
return forEachProperty(symbol, prop => {
1715117164
const propKind = getDeclarationKindFromSymbol(prop);
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(17,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
2+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(20,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
3+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(21,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
4+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(26,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
5+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(29,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
6+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(30,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
7+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(35,10): error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
8+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(38,13): error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
9+
tests/cases/conformance/types/thisType/thisTypeAccessibility.ts(39,13): error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
10+
11+
12+
==== tests/cases/conformance/types/thisType/thisTypeAccessibility.ts (9 errors) ====
13+
class MyClass {
14+
private p: number = 123;
15+
protected pp: number = 123;
16+
public ppp: number = 123;
17+
private static sp: number = 123;
18+
protected static spp: number = 123;
19+
public static sppp: number = 123;
20+
}
21+
22+
interface MyClass {
23+
extension1(p: number): void;
24+
extension2(p: number): void;
25+
extension3(p: number): void;
26+
}
27+
28+
MyClass.prototype.extension1 = function (this: MyClass, p: number) {
29+
this.p = p;
30+
~
31+
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
32+
this.pp = p;
33+
this.ppp = p;
34+
MyClass.sp = p;
35+
~~
36+
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
37+
MyClass.spp = p;
38+
~~~
39+
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
40+
MyClass.sppp = p;
41+
}
42+
43+
MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
44+
this.p = p;
45+
~
46+
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
47+
this.pp = p;
48+
this.ppp = p;
49+
MyClass.sp = p;
50+
~~
51+
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
52+
MyClass.spp = p;
53+
~~~
54+
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
55+
MyClass.sppp = p;
56+
}
57+
58+
function extension3<T extends MyClass> (this: T, p: number) {
59+
this.p = p;
60+
~
61+
!!! error TS2341: Property 'p' is private and only accessible within class 'MyClass'.
62+
this.pp = p;
63+
this.ppp = p;
64+
MyClass.sp = p;
65+
~~
66+
!!! error TS2341: Property 'sp' is private and only accessible within class 'MyClass'.
67+
MyClass.spp = p;
68+
~~~
69+
!!! error TS2445: Property 'spp' is protected and only accessible within class 'MyClass' and its subclasses.
70+
MyClass.sppp = p;
71+
}
72+
73+
MyClass.prototype.extension3 = extension3;
74+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//// [thisTypeAccessibility.ts]
2+
class MyClass {
3+
private p: number = 123;
4+
protected pp: number = 123;
5+
public ppp: number = 123;
6+
private static sp: number = 123;
7+
protected static spp: number = 123;
8+
public static sppp: number = 123;
9+
}
10+
11+
interface MyClass {
12+
extension1(p: number): void;
13+
extension2(p: number): void;
14+
extension3(p: number): void;
15+
}
16+
17+
MyClass.prototype.extension1 = function (this: MyClass, p: number) {
18+
this.p = p;
19+
this.pp = p;
20+
this.ppp = p;
21+
MyClass.sp = p;
22+
MyClass.spp = p;
23+
MyClass.sppp = p;
24+
}
25+
26+
MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
27+
this.p = p;
28+
this.pp = p;
29+
this.ppp = p;
30+
MyClass.sp = p;
31+
MyClass.spp = p;
32+
MyClass.sppp = p;
33+
}
34+
35+
function extension3<T extends MyClass> (this: T, p: number) {
36+
this.p = p;
37+
this.pp = p;
38+
this.ppp = p;
39+
MyClass.sp = p;
40+
MyClass.spp = p;
41+
MyClass.sppp = p;
42+
}
43+
44+
MyClass.prototype.extension3 = extension3;
45+
46+
47+
//// [thisTypeAccessibility.js]
48+
var MyClass = /** @class */ (function () {
49+
function MyClass() {
50+
this.p = 123;
51+
this.pp = 123;
52+
this.ppp = 123;
53+
}
54+
MyClass.sp = 123;
55+
MyClass.spp = 123;
56+
MyClass.sppp = 123;
57+
return MyClass;
58+
}());
59+
MyClass.prototype.extension1 = function (p) {
60+
this.p = p;
61+
this.pp = p;
62+
this.ppp = p;
63+
MyClass.sp = p;
64+
MyClass.spp = p;
65+
MyClass.sppp = p;
66+
};
67+
MyClass.prototype.extension2 = function (p) {
68+
this.p = p;
69+
this.pp = p;
70+
this.ppp = p;
71+
MyClass.sp = p;
72+
MyClass.spp = p;
73+
MyClass.sppp = p;
74+
};
75+
function extension3(p) {
76+
this.p = p;
77+
this.pp = p;
78+
this.ppp = p;
79+
MyClass.sp = p;
80+
MyClass.spp = p;
81+
MyClass.sppp = p;
82+
}
83+
MyClass.prototype.extension3 = extension3;
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
=== tests/cases/conformance/types/thisType/thisTypeAccessibility.ts ===
2+
class MyClass {
3+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
4+
5+
private p: number = 123;
6+
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
7+
8+
protected pp: number = 123;
9+
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
10+
11+
public ppp: number = 123;
12+
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
13+
14+
private static sp: number = 123;
15+
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
16+
17+
protected static spp: number = 123;
18+
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
19+
20+
public static sppp: number = 123;
21+
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
22+
}
23+
24+
interface MyClass {
25+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
26+
27+
extension1(p: number): void;
28+
>extension1 : Symbol(MyClass.extension1, Decl(thisTypeAccessibility.ts, 9, 19))
29+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 10, 15))
30+
31+
extension2(p: number): void;
32+
>extension2 : Symbol(MyClass.extension2, Decl(thisTypeAccessibility.ts, 10, 32))
33+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 11, 15))
34+
35+
extension3(p: number): void;
36+
>extension3 : Symbol(MyClass.extension3, Decl(thisTypeAccessibility.ts, 11, 32))
37+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 12, 15))
38+
}
39+
40+
MyClass.prototype.extension1 = function (this: MyClass, p: number) {
41+
>MyClass.prototype.extension1 : Symbol(MyClass.extension1, Decl(thisTypeAccessibility.ts, 9, 19))
42+
>MyClass.prototype : Symbol(MyClass.prototype)
43+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
44+
>prototype : Symbol(MyClass.prototype)
45+
>extension1 : Symbol(MyClass.extension1, Decl(thisTypeAccessibility.ts, 9, 19))
46+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
47+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
48+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
49+
50+
this.p = p;
51+
>this.p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
52+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
53+
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
54+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
55+
56+
this.pp = p;
57+
>this.pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
58+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
59+
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
60+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
61+
62+
this.ppp = p;
63+
>this.ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
64+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 15, 41))
65+
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
66+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
67+
68+
MyClass.sp = p;
69+
>MyClass.sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
70+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
71+
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
72+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
73+
74+
MyClass.spp = p;
75+
>MyClass.spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
76+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
77+
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
78+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
79+
80+
MyClass.sppp = p;
81+
>MyClass.sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
82+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
83+
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
84+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 15, 55))
85+
}
86+
87+
MyClass.prototype.extension2 = function<T extends MyClass> (this: T, p: number) {
88+
>MyClass.prototype.extension2 : Symbol(MyClass.extension2, Decl(thisTypeAccessibility.ts, 10, 32))
89+
>MyClass.prototype : Symbol(MyClass.prototype)
90+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
91+
>prototype : Symbol(MyClass.prototype)
92+
>extension2 : Symbol(MyClass.extension2, Decl(thisTypeAccessibility.ts, 10, 32))
93+
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 24, 40))
94+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
95+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
96+
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 24, 40))
97+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
98+
99+
this.p = p;
100+
>this.p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
101+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
102+
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
103+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
104+
105+
this.pp = p;
106+
>this.pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
107+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
108+
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
109+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
110+
111+
this.ppp = p;
112+
>this.ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
113+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 24, 60))
114+
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
115+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
116+
117+
MyClass.sp = p;
118+
>MyClass.sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
119+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
120+
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
121+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
122+
123+
MyClass.spp = p;
124+
>MyClass.spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
125+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
126+
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
127+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
128+
129+
MyClass.sppp = p;
130+
>MyClass.sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
131+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
132+
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
133+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 24, 68))
134+
}
135+
136+
function extension3<T extends MyClass> (this: T, p: number) {
137+
>extension3 : Symbol(extension3, Decl(thisTypeAccessibility.ts, 31, 1))
138+
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 33, 20))
139+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
140+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
141+
>T : Symbol(T, Decl(thisTypeAccessibility.ts, 33, 20))
142+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
143+
144+
this.p = p;
145+
>this.p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
146+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
147+
>p : Symbol(MyClass.p, Decl(thisTypeAccessibility.ts, 0, 15))
148+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
149+
150+
this.pp = p;
151+
>this.pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
152+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
153+
>pp : Symbol(MyClass.pp, Decl(thisTypeAccessibility.ts, 1, 28))
154+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
155+
156+
this.ppp = p;
157+
>this.ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
158+
>this : Symbol(this, Decl(thisTypeAccessibility.ts, 33, 40))
159+
>ppp : Symbol(MyClass.ppp, Decl(thisTypeAccessibility.ts, 2, 31))
160+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
161+
162+
MyClass.sp = p;
163+
>MyClass.sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
164+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
165+
>sp : Symbol(MyClass.sp, Decl(thisTypeAccessibility.ts, 3, 29))
166+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
167+
168+
MyClass.spp = p;
169+
>MyClass.spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
170+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
171+
>spp : Symbol(MyClass.spp, Decl(thisTypeAccessibility.ts, 4, 36))
172+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
173+
174+
MyClass.sppp = p;
175+
>MyClass.sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
176+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
177+
>sppp : Symbol(MyClass.sppp, Decl(thisTypeAccessibility.ts, 5, 39))
178+
>p : Symbol(p, Decl(thisTypeAccessibility.ts, 33, 48))
179+
}
180+
181+
MyClass.prototype.extension3 = extension3;
182+
>MyClass.prototype.extension3 : Symbol(MyClass.extension3, Decl(thisTypeAccessibility.ts, 11, 32))
183+
>MyClass.prototype : Symbol(MyClass.prototype)
184+
>MyClass : Symbol(MyClass, Decl(thisTypeAccessibility.ts, 0, 0), Decl(thisTypeAccessibility.ts, 7, 1))
185+
>prototype : Symbol(MyClass.prototype)
186+
>extension3 : Symbol(MyClass.extension3, Decl(thisTypeAccessibility.ts, 11, 32))
187+
>extension3 : Symbol(extension3, Decl(thisTypeAccessibility.ts, 31, 1))
188+

0 commit comments

Comments
 (0)