diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 87aa1e346265d..de979c12882cf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8124,7 +8124,11 @@ namespace ts { // Handle catch clause variables const declaration = symbol.valueDeclaration; if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) { - return anyType; + const decl = declaration as VariableDeclaration; + if (!decl.type) return anyType; + const type = getTypeOfNode(decl.type); + // an errorType will make `checkTryStatement` issue an error + return isTypeAny(type) || type === unknownType ? type : errorType; } // Handle export default expressions if (isSourceFile(declaration) && isJsonSourceFile(declaration)) { @@ -33369,8 +33373,9 @@ namespace ts { if (catchClause) { // Grammar checking if (catchClause.variableDeclaration) { - if (catchClause.variableDeclaration.type) { - grammarErrorOnFirstToken(catchClause.variableDeclaration.type, Diagnostics.Catch_clause_variable_cannot_have_a_type_annotation); + if (catchClause.variableDeclaration.type && getTypeOfNode(catchClause.variableDeclaration) === errorType) { + grammarErrorOnFirstToken(catchClause.variableDeclaration.type, + Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified); } else if (catchClause.variableDeclaration.initializer) { grammarErrorOnFirstToken(catchClause.variableDeclaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1d98e2e6f19a4..1187f8bb4e9ee 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -619,7 +619,7 @@ "category": "Error", "code": 1195 }, - "Catch clause variable cannot have a type annotation.": { + "Catch clause variable type annotation must be 'any' or 'unknown' if specified.": { "category": "Error", "code": 1196 }, diff --git a/tests/baselines/reference/catchClauseWithTypeAnnotation.errors.txt b/tests/baselines/reference/catchClauseWithTypeAnnotation.errors.txt index 5bc7339d2fc93..e5bd5be16ef09 100644 --- a/tests/baselines/reference/catchClauseWithTypeAnnotation.errors.txt +++ b/tests/baselines/reference/catchClauseWithTypeAnnotation.errors.txt @@ -1,9 +1,56 @@ -tests/cases/compiler/catchClauseWithTypeAnnotation.ts(2,13): error TS1196: Catch clause variable cannot have a type annotation. +tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(17,36): error TS2339: Property 'foo' does not exist on type 'unknown'. +tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(18,37): error TS2339: Property 'foo' does not exist on type 'unknown'. +tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(19,23): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. +tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(20,23): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. +tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts(29,29): error TS2492: Cannot redeclare identifier 'x' in catch clause. +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'. -==== tests/cases/compiler/catchClauseWithTypeAnnotation.ts (1 errors) ==== - try { - } catch (e: any) { - ~~~ -!!! error TS1196: Catch clause variable cannot have a type annotation. - } \ No newline at end of file +==== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts (6 errors) ==== + type any1 = any; + type unknown1 = unknown; + + function fn(x: boolean) { + + // no type annotation allowed other than `any` and `unknown` + try { } catch (x) { } // should be OK + try { } catch (x: any) { } // should be OK + try { } catch (x: any1) { } // should be OK + try { } catch (x: unknown) { } // should be OK + try { } catch (x: unknown1) { } // should be OK + try { } catch (x) { x.foo; } // should be OK + try { } catch (x: any) { x.foo; } // should be OK + try { } catch (x: any1) { x.foo; } // should be OK + try { } catch (x: unknown) { console.log(x); } // should be OK + try { } catch (x: unknown1) { console.log(x); } // should be OK + try { } catch (x: unknown) { x.foo; } // error in the body + ~~~ +!!! error TS2339: Property 'foo' does not exist on type 'unknown'. + try { } catch (x: unknown1) { x.foo; } // error in the body + ~~~ +!!! error TS2339: Property 'foo' does not exist on type 'unknown'. + try { } catch (x: Error) { } // error in the type + ~~~~~ +!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. + try { } catch (x: object) { } // error in the type + ~~~~~~ +!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. + + try { console.log(); } + // @ts-ignore + catch (e: number) { // e should not be a `number` + console.log(e.toLowerCase()); + } + + // minor bug: shows that the `catch` argument is skipped when checking scope + try { } catch (x) { let x: string; } + ~ +!!! error TS2492: Cannot redeclare identifier 'x' in catch clause. + try { } catch (x) { var x: string; } + ~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'boolean', but here has type 'string'. +!!! related TS6203 tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts:4:13: 'x' was also declared here. + try { } catch (x) { var x: boolean; } + + } + \ No newline at end of file diff --git a/tests/baselines/reference/catchClauseWithTypeAnnotation.js b/tests/baselines/reference/catchClauseWithTypeAnnotation.js index 097abe0a9caeb..e6ecc235af46b 100644 --- a/tests/baselines/reference/catchClauseWithTypeAnnotation.js +++ b/tests/baselines/reference/catchClauseWithTypeAnnotation.js @@ -1,10 +1,102 @@ //// [catchClauseWithTypeAnnotation.ts] -try { -} catch (e: any) { -} +type any1 = any; +type unknown1 = unknown; + +function fn(x: boolean) { + + // no type annotation allowed other than `any` and `unknown` + try { } catch (x) { } // should be OK + try { } catch (x: any) { } // should be OK + try { } catch (x: any1) { } // should be OK + try { } catch (x: unknown) { } // should be OK + try { } catch (x: unknown1) { } // should be OK + try { } catch (x) { x.foo; } // should be OK + try { } catch (x: any) { x.foo; } // should be OK + try { } catch (x: any1) { x.foo; } // should be OK + try { } catch (x: unknown) { console.log(x); } // should be OK + try { } catch (x: unknown1) { console.log(x); } // should be OK + try { } catch (x: unknown) { x.foo; } // error in the body + try { } catch (x: unknown1) { x.foo; } // error in the body + try { } catch (x: Error) { } // error in the type + try { } catch (x: object) { } // error in the type + + try { console.log(); } + // @ts-ignore + catch (e: number) { // e should not be a `number` + console.log(e.toLowerCase()); + } + + // minor bug: shows that the `catch` argument is skipped when checking scope + try { } catch (x) { let x: string; } + try { } catch (x) { var x: string; } + try { } catch (x) { var x: boolean; } + +} + //// [catchClauseWithTypeAnnotation.js] -try { -} -catch (e) { +function fn(x) { + // no type annotation allowed other than `any` and `unknown` + try { } + catch (x) { } // should be OK + try { } + catch (x) { } // should be OK + try { } + catch (x) { } // should be OK + try { } + catch (x) { } // should be OK + try { } + catch (x) { } // should be OK + try { } + catch (x) { + x.foo; + } // should be OK + try { } + catch (x) { + x.foo; + } // should be OK + try { } + catch (x) { + x.foo; + } // should be OK + try { } + catch (x) { + console.log(x); + } // should be OK + try { } + catch (x) { + console.log(x); + } // should be OK + try { } + catch (x) { + x.foo; + } // error in the body + try { } + catch (x) { + x.foo; + } // error in the body + try { } + catch (x) { } // error in the type + try { } + catch (x) { } // error in the type + try { + console.log(); + } + // @ts-ignore + catch (e) { // e should not be a `number` + console.log(e.toLowerCase()); + } + // minor bug: shows that the `catch` argument is skipped when checking scope + try { } + catch (x) { + var x_1; + } + try { } + catch (x) { + var x; + } + try { } + catch (x) { + var x; + } } diff --git a/tests/baselines/reference/catchClauseWithTypeAnnotation.symbols b/tests/baselines/reference/catchClauseWithTypeAnnotation.symbols index 8358d40a286ad..b8774e2086976 100644 --- a/tests/baselines/reference/catchClauseWithTypeAnnotation.symbols +++ b/tests/baselines/reference/catchClauseWithTypeAnnotation.symbols @@ -1,5 +1,104 @@ -=== tests/cases/compiler/catchClauseWithTypeAnnotation.ts === -try { -} catch (e: any) { ->e : Symbol(e, Decl(catchClauseWithTypeAnnotation.ts, 1, 9)) +=== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts === +type any1 = any; +>any1 : Symbol(any1, Decl(catchClauseWithTypeAnnotation.ts, 0, 0)) + +type unknown1 = unknown; +>unknown1 : Symbol(unknown1, Decl(catchClauseWithTypeAnnotation.ts, 0, 16)) + +function fn(x: boolean) { +>fn : Symbol(fn, Decl(catchClauseWithTypeAnnotation.ts, 1, 24)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 3, 12), Decl(catchClauseWithTypeAnnotation.ts, 29, 27), Decl(catchClauseWithTypeAnnotation.ts, 30, 27)) + + // no type annotation allowed other than `any` and `unknown` + try { } catch (x) { } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 6, 19)) + + try { } catch (x: any) { } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 7, 19)) + + try { } catch (x: any1) { } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 8, 19)) +>any1 : Symbol(any1, Decl(catchClauseWithTypeAnnotation.ts, 0, 0)) + + try { } catch (x: unknown) { } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 9, 19)) + + try { } catch (x: unknown1) { } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 10, 19)) +>unknown1 : Symbol(unknown1, Decl(catchClauseWithTypeAnnotation.ts, 0, 16)) + + try { } catch (x) { x.foo; } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 11, 19)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 11, 19)) + + try { } catch (x: any) { x.foo; } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 12, 19)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 12, 19)) + + try { } catch (x: any1) { x.foo; } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 13, 19)) +>any1 : Symbol(any1, Decl(catchClauseWithTypeAnnotation.ts, 0, 0)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 13, 19)) + + try { } catch (x: unknown) { console.log(x); } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 14, 19)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 14, 19)) + + try { } catch (x: unknown1) { console.log(x); } // should be OK +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 15, 19)) +>unknown1 : Symbol(unknown1, Decl(catchClauseWithTypeAnnotation.ts, 0, 16)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 15, 19)) + + try { } catch (x: unknown) { x.foo; } // error in the body +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 16, 19)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 16, 19)) + + try { } catch (x: unknown1) { x.foo; } // error in the body +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 17, 19)) +>unknown1 : Symbol(unknown1, Decl(catchClauseWithTypeAnnotation.ts, 0, 16)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 17, 19)) + + try { } catch (x: Error) { } // error in the type +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 18, 19)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + try { } catch (x: object) { } // error in the type +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 19, 19)) + + try { console.log(); } +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + // @ts-ignore + catch (e: number) { // e should not be a `number` +>e : Symbol(e, Decl(catchClauseWithTypeAnnotation.ts, 23, 11)) + + console.log(e.toLowerCase()); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>e : Symbol(e, Decl(catchClauseWithTypeAnnotation.ts, 23, 11)) + } + + // minor bug: shows that the `catch` argument is skipped when checking scope + try { } catch (x) { let x: string; } +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 28, 19)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 28, 27)) + + try { } catch (x) { var x: string; } +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 29, 19)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 3, 12), Decl(catchClauseWithTypeAnnotation.ts, 29, 27), Decl(catchClauseWithTypeAnnotation.ts, 30, 27)) + + try { } catch (x) { var x: boolean; } +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 30, 19)) +>x : Symbol(x, Decl(catchClauseWithTypeAnnotation.ts, 3, 12), Decl(catchClauseWithTypeAnnotation.ts, 29, 27), Decl(catchClauseWithTypeAnnotation.ts, 30, 27)) + } + diff --git a/tests/baselines/reference/catchClauseWithTypeAnnotation.types b/tests/baselines/reference/catchClauseWithTypeAnnotation.types index 74ee8463b92a8..a0d1eec0ab590 100644 --- a/tests/baselines/reference/catchClauseWithTypeAnnotation.types +++ b/tests/baselines/reference/catchClauseWithTypeAnnotation.types @@ -1,5 +1,115 @@ -=== tests/cases/compiler/catchClauseWithTypeAnnotation.ts === -try { -} catch (e: any) { +=== tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts === +type any1 = any; +>any1 : any + +type unknown1 = unknown; +>unknown1 : unknown + +function fn(x: boolean) { +>fn : (x: boolean) => void +>x : boolean + + // no type annotation allowed other than `any` and `unknown` + try { } catch (x) { } // should be OK +>x : any + + try { } catch (x: any) { } // should be OK +>x : any + + try { } catch (x: any1) { } // should be OK +>x : any + + try { } catch (x: unknown) { } // should be OK +>x : unknown + + try { } catch (x: unknown1) { } // should be OK +>x : unknown + + try { } catch (x) { x.foo; } // should be OK +>x : any +>x.foo : any +>x : any +>foo : any + + try { } catch (x: any) { x.foo; } // should be OK +>x : any +>x.foo : any +>x : any +>foo : any + + try { } catch (x: any1) { x.foo; } // should be OK +>x : any +>x.foo : any +>x : any +>foo : any + + try { } catch (x: unknown) { console.log(x); } // should be OK +>x : unknown +>console.log(x) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>x : unknown + + try { } catch (x: unknown1) { console.log(x); } // should be OK +>x : unknown +>console.log(x) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>x : unknown + + try { } catch (x: unknown) { x.foo; } // error in the body +>x : unknown +>x.foo : any +>x : unknown +>foo : any + + try { } catch (x: unknown1) { x.foo; } // error in the body +>x : unknown +>x.foo : any +>x : unknown +>foo : any + + try { } catch (x: Error) { } // error in the type +>x : any + + try { } catch (x: object) { } // error in the type +>x : any + + try { console.log(); } +>console.log() : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void + + // @ts-ignore + catch (e: number) { // e should not be a `number` >e : any + + console.log(e.toLowerCase()); +>console.log(e.toLowerCase()) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>e.toLowerCase() : any +>e.toLowerCase : any +>e : any +>toLowerCase : any + } + + // minor bug: shows that the `catch` argument is skipped when checking scope + try { } catch (x) { let x: string; } +>x : any +>x : string + + try { } catch (x) { var x: string; } +>x : any +>x : boolean + + try { } catch (x) { var x: boolean; } +>x : any +>x : boolean + } + diff --git a/tests/baselines/reference/invalidTryStatements.errors.txt b/tests/baselines/reference/invalidTryStatements.errors.txt index a2f8a7bac0c96..0e666dcd8b693 100644 --- a/tests/baselines/reference/invalidTryStatements.errors.txt +++ b/tests/baselines/reference/invalidTryStatements.errors.txt @@ -1,25 +1,44 @@ -tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(8,23): error TS1196: Catch clause variable cannot have a type annotation. -tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(9,23): error TS1196: Catch clause variable cannot have a type annotation. -tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(10,23): error TS1196: Catch clause variable cannot have a type annotation. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(2,5): error TS1005: 'try' expected. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(6,12): error TS1005: 'finally' expected. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(10,5): error TS1005: 'try' expected. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(11,5): error TS1005: 'try' expected. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(15,5): error TS1005: 'try' expected. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(17,5): error TS1005: 'try' expected. +tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts(19,20): error TS1003: Identifier expected. -==== tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts (3 errors) ==== +==== tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts (7 errors) ==== function fn() { - try { - } catch (x) { - var x: string; // ensure x is 'Any' - } + catch(x) { } // error missing try + ~~~~~ +!!! error TS1005: 'try' expected. - // no type annotation allowed - try { } catch (z: any) { } - ~~~ -!!! error TS1196: Catch clause variable cannot have a type annotation. - try { } catch (a: number) { } - ~~~~~~ -!!! error TS1196: Catch clause variable cannot have a type annotation. - try { } catch (y: string) { } - ~~~~~~ -!!! error TS1196: Catch clause variable cannot have a type annotation. + finally { } // potential error; can be absorbed by the 'catch' + + try { }; // error missing finally + ~ +!!! error TS1005: 'finally' expected. } - \ No newline at end of file + function fn2() { + finally { } // error missing try + ~~~~~~~ +!!! error TS1005: 'try' expected. + catch (x) { } // error missing try + ~~~~~ +!!! error TS1005: 'try' expected. + + try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below + + finally { } // error missing try + ~~~~~~~ +!!! error TS1005: 'try' expected. + + catch (x) { } // error missing try + ~~~~~ +!!! error TS1005: 'try' expected. + + try { } catch () { } // error missing catch binding + ~ +!!! error TS1003: Identifier expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidTryStatements.js b/tests/baselines/reference/invalidTryStatements.js index 343ad6e058400..135c2e5685070 100644 --- a/tests/baselines/reference/invalidTryStatements.js +++ b/tests/baselines/reference/invalidTryStatements.js @@ -1,30 +1,51 @@ //// [invalidTryStatements.ts] function fn() { - try { - } catch (x) { - var x: string; // ensure x is 'Any' - } + catch(x) { } // error missing try - // no type annotation allowed - try { } catch (z: any) { } - try { } catch (a: number) { } - try { } catch (y: string) { } + finally { } // potential error; can be absorbed by the 'catch' + + try { }; // error missing finally } - +function fn2() { + finally { } // error missing try + catch (x) { } // error missing try + + try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below + + finally { } // error missing try + + catch (x) { } // error missing try + + try { } catch () { } // error missing catch binding +} //// [invalidTryStatements.js] function fn() { try { } - catch (x) { - var x; // ensure x is 'Any' - } - // no type annotation allowed + catch (x) { } // error missing try + finally { } // potential error; can be absorbed by the 'catch' try { } - catch (z) { } + finally { // error missing finally + } // error missing finally + ; // error missing finally +} +function fn2() { + try { + } + finally { } // error missing try + try { + } + catch (x) { } // error missing try try { } - catch (a) { } + finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below + try { + } + finally { } // error missing try + try { + } + catch (x) { } // error missing try try { } - catch (y) { } + catch () { } // error missing catch binding } diff --git a/tests/baselines/reference/invalidTryStatements.symbols b/tests/baselines/reference/invalidTryStatements.symbols index d3d66657cd71c..294b10ca3e8ec 100644 --- a/tests/baselines/reference/invalidTryStatements.symbols +++ b/tests/baselines/reference/invalidTryStatements.symbols @@ -2,23 +2,28 @@ function fn() { >fn : Symbol(fn, Decl(invalidTryStatements.ts, 0, 0)) - try { - } catch (x) { ->x : Symbol(x, Decl(invalidTryStatements.ts, 2, 13)) + catch(x) { } // error missing try +>x : Symbol(x, Decl(invalidTryStatements.ts, 1, 10)) - var x: string; // ensure x is 'Any' ->x : Symbol(x, Decl(invalidTryStatements.ts, 3, 11)) - } + finally { } // potential error; can be absorbed by the 'catch' - // no type annotation allowed - try { } catch (z: any) { } ->z : Symbol(z, Decl(invalidTryStatements.ts, 7, 19)) + try { }; // error missing finally +} - try { } catch (a: number) { } ->a : Symbol(a, Decl(invalidTryStatements.ts, 8, 19)) +function fn2() { +>fn2 : Symbol(fn2, Decl(invalidTryStatements.ts, 6, 1)) - try { } catch (y: string) { } ->y : Symbol(y, Decl(invalidTryStatements.ts, 9, 19)) -} + finally { } // error missing try + catch (x) { } // error missing try +>x : Symbol(x, Decl(invalidTryStatements.ts, 10, 11)) + + try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below + finally { } // error missing try + + catch (x) { } // error missing try +>x : Symbol(x, Decl(invalidTryStatements.ts, 16, 11)) + try { } catch () { } // error missing catch binding +> : Symbol((Missing), Decl(invalidTryStatements.ts, 18, 19)) +} diff --git a/tests/baselines/reference/invalidTryStatements.types b/tests/baselines/reference/invalidTryStatements.types index 74fb3aad72757..4b4de7d5aa1f2 100644 --- a/tests/baselines/reference/invalidTryStatements.types +++ b/tests/baselines/reference/invalidTryStatements.types @@ -2,23 +2,28 @@ function fn() { >fn : () => void - try { - } catch (x) { + catch(x) { } // error missing try >x : any - var x: string; // ensure x is 'Any' ->x : string - } + finally { } // potential error; can be absorbed by the 'catch' - // no type annotation allowed - try { } catch (z: any) { } ->z : any + try { }; // error missing finally +} - try { } catch (a: number) { } ->a : any +function fn2() { +>fn2 : () => void - try { } catch (y: string) { } ->y : any -} + finally { } // error missing try + catch (x) { } // error missing try +>x : any + + try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below + finally { } // error missing try + + catch (x) { } // error missing try +>x : any + try { } catch () { } // error missing catch binding +> : any +} diff --git a/tests/baselines/reference/invalidTryStatements2.errors.txt b/tests/baselines/reference/invalidTryStatements2.errors.txt deleted file mode 100644 index a7c436236f2e4..0000000000000 --- a/tests/baselines/reference/invalidTryStatements2.errors.txt +++ /dev/null @@ -1,44 +0,0 @@ -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(2,5): error TS1005: 'try' expected. -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(6,12): error TS1005: 'finally' expected. -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(10,5): error TS1005: 'try' expected. -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(11,5): error TS1005: 'try' expected. -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(15,5): error TS1005: 'try' expected. -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(17,5): error TS1005: 'try' expected. -tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts(19,20): error TS1003: Identifier expected. - - -==== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts (7 errors) ==== - function fn() { - catch(x) { } // error missing try - ~~~~~ -!!! error TS1005: 'try' expected. - - finally { } // potential error; can be absorbed by the 'catch' - - try { }; // error missing finally - ~ -!!! error TS1005: 'finally' expected. - } - - function fn2() { - finally { } // error missing try - ~~~~~~~ -!!! error TS1005: 'try' expected. - catch (x) { } // error missing try - ~~~~~ -!!! error TS1005: 'try' expected. - - try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below - - finally { } // error missing try - ~~~~~~~ -!!! error TS1005: 'try' expected. - - catch (x) { } // error missing try - ~~~~~ -!!! error TS1005: 'try' expected. - - try { } catch () { } // error missing catch binding - ~ -!!! error TS1003: Identifier expected. - } \ No newline at end of file diff --git a/tests/baselines/reference/invalidTryStatements2.js b/tests/baselines/reference/invalidTryStatements2.js deleted file mode 100644 index c866626848b43..0000000000000 --- a/tests/baselines/reference/invalidTryStatements2.js +++ /dev/null @@ -1,51 +0,0 @@ -//// [invalidTryStatements2.ts] -function fn() { - catch(x) { } // error missing try - - finally { } // potential error; can be absorbed by the 'catch' - - try { }; // error missing finally -} - -function fn2() { - finally { } // error missing try - catch (x) { } // error missing try - - try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below - - finally { } // error missing try - - catch (x) { } // error missing try - - try { } catch () { } // error missing catch binding -} - -//// [invalidTryStatements2.js] -function fn() { - try { - } - catch (x) { } // error missing try - finally { } // potential error; can be absorbed by the 'catch' - try { } - finally { // error missing finally - } // error missing finally - ; // error missing finally -} -function fn2() { - try { - } - finally { } // error missing try - try { - } - catch (x) { } // error missing try - try { } - finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below - try { - } - finally { } // error missing try - try { - } - catch (x) { } // error missing try - try { } - catch () { } // error missing catch binding -} diff --git a/tests/baselines/reference/invalidTryStatements2.symbols b/tests/baselines/reference/invalidTryStatements2.symbols deleted file mode 100644 index cf64c399d0880..0000000000000 --- a/tests/baselines/reference/invalidTryStatements2.symbols +++ /dev/null @@ -1,29 +0,0 @@ -=== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts === -function fn() { ->fn : Symbol(fn, Decl(invalidTryStatements2.ts, 0, 0)) - - catch(x) { } // error missing try ->x : Symbol(x, Decl(invalidTryStatements2.ts, 1, 10)) - - finally { } // potential error; can be absorbed by the 'catch' - - try { }; // error missing finally -} - -function fn2() { ->fn2 : Symbol(fn2, Decl(invalidTryStatements2.ts, 6, 1)) - - finally { } // error missing try - catch (x) { } // error missing try ->x : Symbol(x, Decl(invalidTryStatements2.ts, 10, 11)) - - try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below - - finally { } // error missing try - - catch (x) { } // error missing try ->x : Symbol(x, Decl(invalidTryStatements2.ts, 16, 11)) - - try { } catch () { } // error missing catch binding -> : Symbol((Missing), Decl(invalidTryStatements2.ts, 18, 19)) -} diff --git a/tests/baselines/reference/invalidTryStatements2.types b/tests/baselines/reference/invalidTryStatements2.types deleted file mode 100644 index bf04220cf141a..0000000000000 --- a/tests/baselines/reference/invalidTryStatements2.types +++ /dev/null @@ -1,29 +0,0 @@ -=== tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts === -function fn() { ->fn : () => void - - catch(x) { } // error missing try ->x : any - - finally { } // potential error; can be absorbed by the 'catch' - - try { }; // error missing finally -} - -function fn2() { ->fn2 : () => void - - finally { } // error missing try - catch (x) { } // error missing try ->x : any - - try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below - - finally { } // error missing try - - catch (x) { } // error missing try ->x : any - - try { } catch () { } // error missing catch binding -> : any -} diff --git a/tests/baselines/reference/parserCatchClauseWithTypeAnnotation1.errors.txt b/tests/baselines/reference/parserCatchClauseWithTypeAnnotation1.errors.txt index a1f1d1fd6c7fa..f16fb86f50be6 100644 --- a/tests/baselines/reference/parserCatchClauseWithTypeAnnotation1.errors.txt +++ b/tests/baselines/reference/parserCatchClauseWithTypeAnnotation1.errors.txt @@ -1,10 +1,10 @@ -tests/cases/conformance/parser/ecmascript5/CatchClauses/parserCatchClauseWithTypeAnnotation1.ts(2,13): error TS1196: Catch clause variable cannot have a type annotation. +tests/cases/conformance/parser/ecmascript5/CatchClauses/parserCatchClauseWithTypeAnnotation1.ts(2,13): error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. ==== tests/cases/conformance/parser/ecmascript5/CatchClauses/parserCatchClauseWithTypeAnnotation1.ts (1 errors) ==== try { } catch (e: Error) { ~~~~~ -!!! error TS1196: Catch clause variable cannot have a type annotation. +!!! error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. } \ No newline at end of file diff --git a/tests/cases/compiler/catchClauseWithTypeAnnotation.ts b/tests/cases/compiler/catchClauseWithTypeAnnotation.ts deleted file mode 100644 index e9462c272fe18..0000000000000 --- a/tests/cases/compiler/catchClauseWithTypeAnnotation.ts +++ /dev/null @@ -1,3 +0,0 @@ -try { -} catch (e: any) { -} \ No newline at end of file diff --git a/tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts b/tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts new file mode 100644 index 0000000000000..e33aa3ba4451a --- /dev/null +++ b/tests/cases/conformance/statements/tryStatements/catchClauseWithTypeAnnotation.ts @@ -0,0 +1,33 @@ +type any1 = any; +type unknown1 = unknown; + +function fn(x: boolean) { + + // no type annotation allowed other than `any` and `unknown` + try { } catch (x) { } // should be OK + try { } catch (x: any) { } // should be OK + try { } catch (x: any1) { } // should be OK + try { } catch (x: unknown) { } // should be OK + try { } catch (x: unknown1) { } // should be OK + try { } catch (x) { x.foo; } // should be OK + try { } catch (x: any) { x.foo; } // should be OK + try { } catch (x: any1) { x.foo; } // should be OK + try { } catch (x: unknown) { console.log(x); } // should be OK + try { } catch (x: unknown1) { console.log(x); } // should be OK + try { } catch (x: unknown) { x.foo; } // error in the body + try { } catch (x: unknown1) { x.foo; } // error in the body + try { } catch (x: Error) { } // error in the type + try { } catch (x: object) { } // error in the type + + try { console.log(); } + // @ts-ignore + catch (e: number) { // e should not be a `number` + console.log(e.toLowerCase()); + } + + // minor bug: shows that the `catch` argument is skipped when checking scope + try { } catch (x) { let x: string; } + try { } catch (x) { var x: string; } + try { } catch (x) { var x: boolean; } + +} diff --git a/tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts b/tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts index c838cf45f6948..7fb1b135c906b 100644 --- a/tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts +++ b/tests/cases/conformance/statements/tryStatements/invalidTryStatements.ts @@ -1,12 +1,20 @@ function fn() { - try { - } catch (x) { - var x: string; // ensure x is 'Any' - } - - // no type annotation allowed - try { } catch (z: any) { } - try { } catch (a: number) { } - try { } catch (y: string) { } + catch(x) { } // error missing try + + finally { } // potential error; can be absorbed by the 'catch' + + try { }; // error missing finally } +function fn2() { + finally { } // error missing try + catch (x) { } // error missing try + + try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below + + finally { } // error missing try + + catch (x) { } // error missing try + + try { } catch () { } // error missing catch binding +} \ No newline at end of file diff --git a/tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts b/tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts deleted file mode 100644 index 7fb1b135c906b..0000000000000 --- a/tests/cases/conformance/statements/tryStatements/invalidTryStatements2.ts +++ /dev/null @@ -1,20 +0,0 @@ -function fn() { - catch(x) { } // error missing try - - finally { } // potential error; can be absorbed by the 'catch' - - try { }; // error missing finally -} - -function fn2() { - finally { } // error missing try - catch (x) { } // error missing try - - try { } finally { } // statement is here, so the 'catch' clause above doesn't absorb errors from the 'finally' clause below - - finally { } // error missing try - - catch (x) { } // error missing try - - try { } catch () { } // error missing catch binding -} \ No newline at end of file