Skip to content

Commit e10853f

Browse files
committed
handle boolean literals
1 parent 332ecc3 commit e10853f

File tree

5 files changed

+259
-27
lines changed

5 files changed

+259
-27
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38802,6 +38802,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3880238802
}
3880338803
const expr = skipParentheses(singleReturn, /*excludeJSDocTypeAssertions*/ true);
3880438804
const returnType = checkExpressionCached(expr);
38805+
if (contextualTypePredicate && returnType.flags & TypeFlags.BooleanLiteral) {
38806+
const param = func.parameters[contextualTypePredicate.parameterIndex];
38807+
if (!isIdentifier(param.name)) {
38808+
return undefined;
38809+
}
38810+
const refinedType = (returnType as IntrinsicType).intrinsicName === "true" ? getTypeOfSymbol(param.symbol) : neverType;
38811+
return createTypePredicate(TypePredicateKind.Identifier, unescapeLeadingUnderscores(param.name.escapedText), contextualTypePredicate.parameterIndex, refinedType);
38812+
}
3880538813
if (!(returnType.flags & TypeFlags.Boolean)) return undefined;
3880638814
return contextualTypePredicate ?
3880738815
getTypePredicateIfRefinesParameterAtIndex(func, expr, contextualTypePredicate, contextualTypePredicate.parameterIndex) :
Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
inferContextualTypePredicates1.ts(13,26): error TS2345: Argument of type '(item: Foo | Bar) => false' is not assignable to parameter of type '(a: Foo | Bar) => a is Foo | Bar'.
2-
Signature '(item: Foo | Bar): false' must be a type predicate.
3-
inferContextualTypePredicates1.ts(14,26): error TS2345: Argument of type '(item: Foo | Bar) => true' is not assignable to parameter of type '(a: Foo | Bar) => a is Foo | Bar'.
4-
Signature '(item: Foo | Bar): true' must be a type predicate.
51
inferContextualTypePredicates1.ts(17,7): error TS2322: Type '(a: string | null, b: string | null) => boolean' is not assignable to type '(a: string | null, b: string | null) => b is string'.
62
Signature '(a: string | null, b: string | null): boolean' must be a type predicate.
73

84

9-
==== inferContextualTypePredicates1.ts (3 errors) ====
5+
==== inferContextualTypePredicates1.ts (1 errors) ====
106
type Foo = { type: "foo"; foo: number };
117
type Bar = { type: "bar"; bar: string };
128

@@ -19,18 +15,31 @@ inferContextualTypePredicates1.ts(17,7): error TS2322: Type '(a: string | null,
1915

2016
const r1 = skipIf(items, (item) => item.type === "foo"); // ok
2117
const r2 = skipIf(items, (item) => item.type === "foo" || item.type === "bar"); // ok
22-
const r3 = skipIf(items, (item) => false); // error
23-
~~~~~~~~~~~~~~~
24-
!!! error TS2345: Argument of type '(item: Foo | Bar) => false' is not assignable to parameter of type '(a: Foo | Bar) => a is Foo | Bar'.
25-
!!! error TS2345: Signature '(item: Foo | Bar): false' must be a type predicate.
26-
const r4 = skipIf(items, (item) => true); // error
27-
~~~~~~~~~~~~~~
28-
!!! error TS2345: Argument of type '(item: Foo | Bar) => true' is not assignable to parameter of type '(a: Foo | Bar) => a is Foo | Bar'.
29-
!!! error TS2345: Signature '(item: Foo | Bar): true' must be a type predicate.
18+
const r3 = skipIf(items, (item) => false); // ok
19+
const r4 = skipIf(items, (item) => true); // ok
3020

3121
const pred1: (a: string | null, b: string | null) => b is string = (a, b) => typeof b === 'string'; // ok
3222
const pred2: (a: string | null, b: string | null) => b is string = (a, b) => typeof a === 'string'; // error
3323
~~~~~
3424
!!! error TS2322: Type '(a: string | null, b: string | null) => boolean' is not assignable to type '(a: string | null, b: string | null) => b is string'.
3525
!!! error TS2322: Signature '(a: string | null, b: string | null): boolean' must be a type predicate.
26+
27+
export declare function every<T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[];
28+
export declare function every<T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined;
29+
export declare function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean;
30+
31+
type Type = {
32+
kind: number;
33+
flags: number;
34+
};
35+
36+
function testEvery(typeSet: Type[]) {
37+
if (every(typeSet, (t) => t.kind === 1)) {
38+
return 1;
39+
}
40+
if (every(typeSet, (t) => t.kind === 2)) {
41+
return 2;
42+
}
43+
return -1;
44+
}
3645

tests/baselines/reference/inferContextualTypePredicates1.symbols

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ const r2 = skipIf(items, (item) => item.type === "foo" || item.type === "bar");
5959
>item : Symbol(item, Decl(inferContextualTypePredicates1.ts, 11, 26))
6060
>type : Symbol(type, Decl(inferContextualTypePredicates1.ts, 1, 12))
6161

62-
const r3 = skipIf(items, (item) => false); // error
62+
const r3 = skipIf(items, (item) => false); // ok
6363
>r3 : Symbol(r3, Decl(inferContextualTypePredicates1.ts, 12, 5))
6464
>skipIf : Symbol(skipIf, Decl(inferContextualTypePredicates1.ts, 1, 40))
6565
>items : Symbol(items, Decl(inferContextualTypePredicates1.ts, 8, 13))
6666
>item : Symbol(item, Decl(inferContextualTypePredicates1.ts, 12, 26))
6767

68-
const r4 = skipIf(items, (item) => true); // error
68+
const r4 = skipIf(items, (item) => true); // ok
6969
>r4 : Symbol(r4, Decl(inferContextualTypePredicates1.ts, 13, 5))
7070
>skipIf : Symbol(skipIf, Decl(inferContextualTypePredicates1.ts, 1, 40))
7171
>items : Symbol(items, Decl(inferContextualTypePredicates1.ts, 8, 13))
@@ -89,3 +89,84 @@ const pred2: (a: string | null, b: string | null) => b is string = (a, b) => typ
8989
>b : Symbol(b, Decl(inferContextualTypePredicates1.ts, 16, 70))
9090
>a : Symbol(a, Decl(inferContextualTypePredicates1.ts, 16, 68))
9191

92+
export declare function every<T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[];
93+
>every : Symbol(every, Decl(inferContextualTypePredicates1.ts, 16, 99), Decl(inferContextualTypePredicates1.ts, 18, 145), Decl(inferContextualTypePredicates1.ts, 19, 169))
94+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 18, 30))
95+
>U : Symbol(U, Decl(inferContextualTypePredicates1.ts, 18, 32))
96+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 18, 30))
97+
>array : Symbol(array, Decl(inferContextualTypePredicates1.ts, 18, 46))
98+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 18, 30))
99+
>callback : Symbol(callback, Decl(inferContextualTypePredicates1.ts, 18, 66))
100+
>element : Symbol(element, Decl(inferContextualTypePredicates1.ts, 18, 78))
101+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 18, 30))
102+
>index : Symbol(index, Decl(inferContextualTypePredicates1.ts, 18, 89))
103+
>element : Symbol(element, Decl(inferContextualTypePredicates1.ts, 18, 78))
104+
>U : Symbol(U, Decl(inferContextualTypePredicates1.ts, 18, 32))
105+
>array : Symbol(array, Decl(inferContextualTypePredicates1.ts, 18, 46))
106+
>U : Symbol(U, Decl(inferContextualTypePredicates1.ts, 18, 32))
107+
108+
export declare function every<T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined;
109+
>every : Symbol(every, Decl(inferContextualTypePredicates1.ts, 16, 99), Decl(inferContextualTypePredicates1.ts, 18, 145), Decl(inferContextualTypePredicates1.ts, 19, 169))
110+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 19, 30))
111+
>U : Symbol(U, Decl(inferContextualTypePredicates1.ts, 19, 32))
112+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 19, 30))
113+
>array : Symbol(array, Decl(inferContextualTypePredicates1.ts, 19, 46))
114+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 19, 30))
115+
>callback : Symbol(callback, Decl(inferContextualTypePredicates1.ts, 19, 78))
116+
>element : Symbol(element, Decl(inferContextualTypePredicates1.ts, 19, 90))
117+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 19, 30))
118+
>index : Symbol(index, Decl(inferContextualTypePredicates1.ts, 19, 101))
119+
>element : Symbol(element, Decl(inferContextualTypePredicates1.ts, 19, 90))
120+
>U : Symbol(U, Decl(inferContextualTypePredicates1.ts, 19, 32))
121+
>array : Symbol(array, Decl(inferContextualTypePredicates1.ts, 19, 46))
122+
>U : Symbol(U, Decl(inferContextualTypePredicates1.ts, 19, 32))
123+
124+
export declare function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean;
125+
>every : Symbol(every, Decl(inferContextualTypePredicates1.ts, 16, 99), Decl(inferContextualTypePredicates1.ts, 18, 145), Decl(inferContextualTypePredicates1.ts, 19, 169))
126+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 20, 30))
127+
>array : Symbol(array, Decl(inferContextualTypePredicates1.ts, 20, 33))
128+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 20, 30))
129+
>callback : Symbol(callback, Decl(inferContextualTypePredicates1.ts, 20, 65))
130+
>element : Symbol(element, Decl(inferContextualTypePredicates1.ts, 20, 77))
131+
>T : Symbol(T, Decl(inferContextualTypePredicates1.ts, 20, 30))
132+
>index : Symbol(index, Decl(inferContextualTypePredicates1.ts, 20, 88))
133+
134+
type Type = {
135+
>Type : Symbol(Type, Decl(inferContextualTypePredicates1.ts, 20, 125))
136+
137+
kind: number;
138+
>kind : Symbol(kind, Decl(inferContextualTypePredicates1.ts, 22, 13))
139+
140+
flags: number;
141+
>flags : Symbol(flags, Decl(inferContextualTypePredicates1.ts, 23, 15))
142+
143+
};
144+
145+
function testEvery(typeSet: Type[]) {
146+
>testEvery : Symbol(testEvery, Decl(inferContextualTypePredicates1.ts, 25, 2))
147+
>typeSet : Symbol(typeSet, Decl(inferContextualTypePredicates1.ts, 27, 19))
148+
>Type : Symbol(Type, Decl(inferContextualTypePredicates1.ts, 20, 125))
149+
150+
if (every(typeSet, (t) => t.kind === 1)) {
151+
>every : Symbol(every, Decl(inferContextualTypePredicates1.ts, 16, 99), Decl(inferContextualTypePredicates1.ts, 18, 145), Decl(inferContextualTypePredicates1.ts, 19, 169))
152+
>typeSet : Symbol(typeSet, Decl(inferContextualTypePredicates1.ts, 27, 19))
153+
>t : Symbol(t, Decl(inferContextualTypePredicates1.ts, 28, 22))
154+
>t.kind : Symbol(kind, Decl(inferContextualTypePredicates1.ts, 22, 13))
155+
>t : Symbol(t, Decl(inferContextualTypePredicates1.ts, 28, 22))
156+
>kind : Symbol(kind, Decl(inferContextualTypePredicates1.ts, 22, 13))
157+
158+
return 1;
159+
}
160+
if (every(typeSet, (t) => t.kind === 2)) {
161+
>every : Symbol(every, Decl(inferContextualTypePredicates1.ts, 16, 99), Decl(inferContextualTypePredicates1.ts, 18, 145), Decl(inferContextualTypePredicates1.ts, 19, 169))
162+
>typeSet : Symbol(typeSet, Decl(inferContextualTypePredicates1.ts, 27, 19))
163+
>t : Symbol(t, Decl(inferContextualTypePredicates1.ts, 31, 22))
164+
>t.kind : Symbol(kind, Decl(inferContextualTypePredicates1.ts, 22, 13))
165+
>t : Symbol(t, Decl(inferContextualTypePredicates1.ts, 31, 22))
166+
>kind : Symbol(kind, Decl(inferContextualTypePredicates1.ts, 22, 13))
167+
168+
return 2;
169+
}
170+
return -1;
171+
}
172+

tests/baselines/reference/inferContextualTypePredicates1.types

Lines changed: 125 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,23 @@ const r2 = skipIf(items, (item) => item.type === "foo" || item.type === "bar");
9797
>"bar" : "bar"
9898
> : ^^^^^
9999

100-
const r3 = skipIf(items, (item) => false); // error
101-
>r3 : never[]
102-
> : ^^^^^^^
103-
>skipIf(items, (item) => false) : never[]
104-
> : ^^^^^^^
100+
const r3 = skipIf(items, (item) => false); // ok
101+
>r3 : (Foo | Bar)[]
102+
> : ^^^^^^^^^^^^^
103+
>skipIf(items, (item) => false) : (Foo | Bar)[]
104+
> : ^^^^^^^^^^^^^
105105
>skipIf : <A, B extends A>(as: A[], predicate: (a: A) => a is B) => Exclude<A, B>[]
106106
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
107107
>items : (Foo | Bar)[]
108108
> : ^^^^^^^^^^^^^
109-
>(item) => false : (item: Foo | Bar) => false
110-
> : ^ ^^^^^^^^^^^^^^^^^^^^^
109+
>(item) => false : (item: Foo | Bar) => item is never
110+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111111
>item : Foo | Bar
112112
> : ^^^^^^^^^
113113
>false : false
114114
> : ^^^^^
115115

116-
const r4 = skipIf(items, (item) => true); // error
116+
const r4 = skipIf(items, (item) => true); // ok
117117
>r4 : never[]
118118
> : ^^^^^^^
119119
>skipIf(items, (item) => true) : never[]
@@ -122,8 +122,8 @@ const r4 = skipIf(items, (item) => true); // error
122122
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
123123
>items : (Foo | Bar)[]
124124
> : ^^^^^^^^^^^^^
125-
>(item) => true : (item: Foo | Bar) => true
126-
> : ^ ^^^^^^^^^^^^^^^^^^^^
125+
>(item) => true : (item: Foo | Bar) => item is Foo | Bar
126+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
127127
>item : Foo | Bar
128128
> : ^^^^^^^^^
129129
>true : true
@@ -173,3 +173,118 @@ const pred2: (a: string | null, b: string | null) => b is string = (a, b) => typ
173173
>'string' : "string"
174174
> : ^^^^^^^^
175175

176+
export declare function every<T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[];
177+
>every : { <T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[]; <T_1, U_1 extends T_1>(array: readonly T_1[] | undefined, callback: (element: T_1, index: number) => element is U_1): array is readonly U_1[] | undefined; <T_1>(array: readonly T_1[] | undefined, callback: (element: T_1, index: number) => boolean): boolean; }
178+
> : ^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^^^^ ^^ ^^ ^^ ^^^ ^^^
179+
>array : readonly T[]
180+
> : ^^^^^^^^^^^^
181+
>callback : (element: T, index: number) => element is U
182+
> : ^ ^^ ^^ ^^ ^^^^^
183+
>element : T
184+
> : ^
185+
>index : number
186+
> : ^^^^^^
187+
188+
export declare function every<T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined;
189+
>every : { <T_1, U_1 extends T_1>(array: readonly T_1[], callback: (element: T_1, index: number) => element is U_1): array is readonly U_1[]; <T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined; <T_1>(array: readonly T_1[] | undefined, callback: (element: T_1, index: number) => boolean): boolean; }
190+
> : ^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^^^^ ^^ ^^ ^^ ^^^ ^^^
191+
>array : readonly T[] | undefined
192+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
193+
>callback : (element: T, index: number) => element is U
194+
> : ^ ^^ ^^ ^^ ^^^^^
195+
>element : T
196+
> : ^
197+
>index : number
198+
> : ^^^^^^
199+
200+
export declare function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean;
201+
>every : { <T_1, U extends T_1>(array: readonly T_1[], callback: (element: T_1, index: number) => element is U): array is readonly U[]; <T_1, U extends T_1>(array: readonly T_1[] | undefined, callback: (element: T_1, index: number) => element is U): array is readonly U[] | undefined; <T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean; }
202+
> : ^^^^^^^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^^^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^
203+
>array : readonly T[] | undefined
204+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
205+
>callback : (element: T, index: number) => boolean
206+
> : ^ ^^ ^^ ^^ ^^^^^
207+
>element : T
208+
> : ^
209+
>index : number
210+
> : ^^^^^^
211+
212+
type Type = {
213+
>Type : Type
214+
> : ^^^^
215+
216+
kind: number;
217+
>kind : number
218+
> : ^^^^^^
219+
220+
flags: number;
221+
>flags : number
222+
> : ^^^^^^
223+
224+
};
225+
226+
function testEvery(typeSet: Type[]) {
227+
>testEvery : (typeSet: Type[]) => 1 | 2 | -1
228+
> : ^ ^^ ^^^^^^^^^^^^^^^
229+
>typeSet : Type[]
230+
> : ^^^^^^
231+
232+
if (every(typeSet, (t) => t.kind === 1)) {
233+
>every(typeSet, (t) => t.kind === 1) : boolean
234+
> : ^^^^^^^
235+
>every : { <T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[]; <T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined; <T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean; }
236+
> : ^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^
237+
>typeSet : Type[]
238+
> : ^^^^^^
239+
>(t) => t.kind === 1 : (t: Type) => boolean
240+
> : ^ ^^^^^^^^^^^^^^^^^^
241+
>t : Type
242+
> : ^^^^
243+
>t.kind === 1 : boolean
244+
> : ^^^^^^^
245+
>t.kind : number
246+
> : ^^^^^^
247+
>t : Type
248+
> : ^^^^
249+
>kind : number
250+
> : ^^^^^^
251+
>1 : 1
252+
> : ^
253+
254+
return 1;
255+
>1 : 1
256+
> : ^
257+
}
258+
if (every(typeSet, (t) => t.kind === 2)) {
259+
>every(typeSet, (t) => t.kind === 2) : boolean
260+
> : ^^^^^^^
261+
>every : { <T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[]; <T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined; <T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean; }
262+
> : ^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^
263+
>typeSet : Type[]
264+
> : ^^^^^^
265+
>(t) => t.kind === 2 : (t: Type) => boolean
266+
> : ^ ^^^^^^^^^^^^^^^^^^
267+
>t : Type
268+
> : ^^^^
269+
>t.kind === 2 : boolean
270+
> : ^^^^^^^
271+
>t.kind : number
272+
> : ^^^^^^
273+
>t : Type
274+
> : ^^^^
275+
>kind : number
276+
> : ^^^^^^
277+
>2 : 2
278+
> : ^
279+
280+
return 2;
281+
>2 : 2
282+
> : ^
283+
}
284+
return -1;
285+
>-1 : -1
286+
> : ^^
287+
>1 : 1
288+
> : ^
289+
}
290+

tests/cases/compiler/inferContextualTypePredicates1.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,27 @@ declare const items: (Foo | Bar)[];
1313

1414
const r1 = skipIf(items, (item) => item.type === "foo"); // ok
1515
const r2 = skipIf(items, (item) => item.type === "foo" || item.type === "bar"); // ok
16-
const r3 = skipIf(items, (item) => false); // error
17-
const r4 = skipIf(items, (item) => true); // error
16+
const r3 = skipIf(items, (item) => false); // ok
17+
const r4 = skipIf(items, (item) => true); // ok
1818

1919
const pred1: (a: string | null, b: string | null) => b is string = (a, b) => typeof b === 'string'; // ok
2020
const pred2: (a: string | null, b: string | null) => b is string = (a, b) => typeof a === 'string'; // error
21+
22+
export declare function every<T, U extends T>(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[];
23+
export declare function every<T, U extends T>(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined;
24+
export declare function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean;
25+
26+
type Type = {
27+
kind: number;
28+
flags: number;
29+
};
30+
31+
function testEvery(typeSet: Type[]) {
32+
if (every(typeSet, (t) => t.kind === 1)) {
33+
return 1;
34+
}
35+
if (every(typeSet, (t) => t.kind === 2)) {
36+
return 2;
37+
}
38+
return -1;
39+
}

0 commit comments

Comments
 (0)