Skip to content

Commit 1508446

Browse files
authored
fix(40222): fix crash on using destructuring in a catch clause (#40240)
1 parent fa89ce6 commit 1508446

File tree

6 files changed

+137
-6
lines changed

6 files changed

+137
-6
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34237,12 +34237,15 @@ namespace ts {
3423734237
if (catchClause) {
3423834238
// Grammar checking
3423934239
if (catchClause.variableDeclaration) {
34240-
if (catchClause.variableDeclaration.type && getTypeOfNode(catchClause.variableDeclaration) === errorType) {
34241-
grammarErrorOnFirstToken(catchClause.variableDeclaration.type,
34242-
Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified);
34240+
const declaration = catchClause.variableDeclaration;
34241+
if (declaration.type) {
34242+
const type = getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ false);
34243+
if (type && !(type.flags & TypeFlags.AnyOrUnknown)) {
34244+
grammarErrorOnFirstToken(declaration.type, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified);
34245+
}
3424334246
}
34244-
else if (catchClause.variableDeclaration.initializer) {
34245-
grammarErrorOnFirstToken(catchClause.variableDeclaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer);
34247+
else if (declaration.initializer) {
34248+
grammarErrorOnFirstToken(declaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer);
3424634249
}
3424734250
else {
3424834251
const blockLocals = catchClause.block.locals;

tests/baselines/reference/catchClauseWithTypeAnnotation.errors.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.t
44
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(20,23): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
55
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(29,29): error TS2492: Cannot redeclare identifier 'x' in catch clause.
66
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(30,29): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'boolean', but here has type 'string'.
7+
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(38,27): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
8+
tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(39,27): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
79

810

9-
==== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts (6 errors) ====
11+
==== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts (8 errors) ====
1012
type any1 = any;
1113
type unknown1 = unknown;
1214

@@ -52,5 +54,16 @@ tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.t
5254
!!! related TS6203 tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts:4:13: 'x' was also declared here.
5355
try { } catch (x) { var x: boolean; }
5456

57+
try { } catch ({ x }) { } // should be OK
58+
try { } catch ({ x }: any) { x.foo; } // should be OK
59+
try { } catch ({ x }: any1) { x.foo;} // should be OK
60+
try { } catch ({ x }: unknown) { console.log(x); } // should be OK
61+
try { } catch ({ x }: unknown1) { console.log(x); } // should be OK
62+
try { } catch ({ x }: object) { } // error in the type
63+
~~~~~~
64+
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
65+
try { } catch ({ x }: Error) { } // error in the type
66+
~~~~~
67+
!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified.
5568
}
5669

tests/baselines/reference/catchClauseWithTypeAnnotation.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ function fn(x: boolean) {
3131
try { } catch (x) { var x: string; }
3232
try { } catch (x) { var x: boolean; }
3333

34+
try { } catch ({ x }) { } // should be OK
35+
try { } catch ({ x }: any) { x.foo; } // should be OK
36+
try { } catch ({ x }: any1) { x.foo;} // should be OK
37+
try { } catch ({ x }: unknown) { console.log(x); } // should be OK
38+
try { } catch ({ x }: unknown1) { console.log(x); } // should be OK
39+
try { } catch ({ x }: object) { } // error in the type
40+
try { } catch ({ x }: Error) { } // error in the type
3441
}
3542

3643

@@ -99,4 +106,36 @@ function fn(x) {
99106
catch (x) {
100107
var x;
101108
}
109+
try { }
110+
catch (_a) {
111+
var x_2 = _a.x;
112+
} // should be OK
113+
try { }
114+
catch (_b) {
115+
var x_3 = _b.x;
116+
x_3.foo;
117+
} // should be OK
118+
try { }
119+
catch (_c) {
120+
var x_4 = _c.x;
121+
x_4.foo;
122+
} // should be OK
123+
try { }
124+
catch (_d) {
125+
var x_5 = _d.x;
126+
console.log(x_5);
127+
} // should be OK
128+
try { }
129+
catch (_e) {
130+
var x_6 = _e.x;
131+
console.log(x_6);
132+
} // should be OK
133+
try { }
134+
catch (_f) {
135+
var x_7 = _f.x;
136+
} // error in the type
137+
try { }
138+
catch (_g) {
139+
var x_8 = _g.x;
140+
} // error in the type
102141
}

tests/baselines/reference/catchClauseWithTypeAnnotation.symbols

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,38 @@ function fn(x: boolean) {
100100
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 30, 19))
101101
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 3, 12), Decl(catchClauseWithTypeAnnotation.ts, 29, 27), Decl(catchClauseWithTypeAnnotation.ts, 30, 27))
102102

103+
try { } catch ({ x }) { } // should be OK
104+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 32, 20))
105+
106+
try { } catch ({ x }: any) { x.foo; } // should be OK
107+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 33, 20))
108+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 33, 20))
109+
110+
try { } catch ({ x }: any1) { x.foo;} // should be OK
111+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 34, 20))
112+
>any1 : Symbol(any1, Decl(catchClauseWithTypeAnnotation.ts, 0, 0))
113+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 34, 20))
114+
115+
try { } catch ({ x }: unknown) { console.log(x); } // should be OK
116+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 35, 20))
117+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
118+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
119+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
120+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 35, 20))
121+
122+
try { } catch ({ x }: unknown1) { console.log(x); } // should be OK
123+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 36, 20))
124+
>unknown1 : Symbol(unknown1, Decl(catchClauseWithTypeAnnotation.ts, 0, 16))
125+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
126+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
127+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
128+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 36, 20))
129+
130+
try { } catch ({ x }: object) { } // error in the type
131+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 37, 20))
132+
133+
try { } catch ({ x }: Error) { } // error in the type
134+
>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 38, 20))
135+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
103136
}
104137

tests/baselines/reference/catchClauseWithTypeAnnotation.types

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,41 @@ function fn(x: boolean) {
111111
>x : any
112112
>x : boolean
113113

114+
try { } catch ({ x }) { } // should be OK
115+
>x : any
116+
117+
try { } catch ({ x }: any) { x.foo; } // should be OK
118+
>x : any
119+
>x.foo : any
120+
>x : any
121+
>foo : any
122+
123+
try { } catch ({ x }: any1) { x.foo;} // should be OK
124+
>x : any
125+
>x.foo : any
126+
>x : any
127+
>foo : any
128+
129+
try { } catch ({ x }: unknown) { console.log(x); } // should be OK
130+
>x : any
131+
>console.log(x) : void
132+
>console.log : (...data: any[]) => void
133+
>console : Console
134+
>log : (...data: any[]) => void
135+
>x : any
136+
137+
try { } catch ({ x }: unknown1) { console.log(x); } // should be OK
138+
>x : any
139+
>console.log(x) : void
140+
>console.log : (...data: any[]) => void
141+
>console : Console
142+
>log : (...data: any[]) => void
143+
>x : any
144+
145+
try { } catch ({ x }: object) { } // error in the type
146+
>x : any
147+
148+
try { } catch ({ x }: Error) { } // error in the type
149+
>x : any
114150
}
115151

tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,11 @@ function fn(x: boolean) {
3030
try { } catch (x) { var x: string; }
3131
try { } catch (x) { var x: boolean; }
3232

33+
try { } catch ({ x }) { } // should be OK
34+
try { } catch ({ x }: any) { x.foo; } // should be OK
35+
try { } catch ({ x }: any1) { x.foo;} // should be OK
36+
try { } catch ({ x }: unknown) { console.log(x); } // should be OK
37+
try { } catch ({ x }: unknown1) { console.log(x); } // should be OK
38+
try { } catch ({ x }: object) { } // error in the type
39+
try { } catch ({ x }: Error) { } // error in the type
3340
}

0 commit comments

Comments
 (0)