Skip to content

Ignored catch parameter - #17517

Merged
Ron Buckton (rbuckton) merged 17 commits into
microsoft:masterfrom
tinganho:IgnoredCatchParameter
Aug 8, 2017
Merged

Ron Buckton (rbuckton) merged 17 commits into
microsoft:masterfrom
tinganho:IgnoredCatchParameter

Conversation

@tinganho

Copy link
Copy Markdown
Contributor

Fixes #17467

Comment thread src/compiler/diagnosticMessages.json Outdated
"category": "Error",
"code": 2713
},
"Duplicate identifier '_ignoredCatchParameter'. Compiler uses the parameter declaration '_ignoredCatchParameter' to bind ignored catched exceptions.": {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you still need this:

Compiler uses the declaration '_ignoredCatchBinding` to bind ignored 'catch' clause parameters.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

Comment thread src/compiler/transformers/esnext.ts Outdated

function visitCatchClause(node: CatchClause): CatchClause {
if (!node.variableDeclaration) {
return updateCatchClause(node, createVariableDeclaration("_ignoredCatchParameter"), node.block);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of createVariableDeclaration, we have a createUniqueName that you can call, which relieves you of having to write the error out. I think Ryan Cavanaugh (@RyanCavanaugh) was just joking about reserving a variable name (but I'm not sure 😄 ).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you should either use createUniqueName or createTempVariable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added createTempVariable(undefined) here.

@DanielRosenwasser

Daniel Rosenwasser (DanielRosenwasser) commented Jul 31, 2017 •

Copy link
Copy Markdown
Member

Looks great other than the unique identifier change I suggested (which may lead you to remove some tests relating to reserving these identifiers).

I think Ron Buckton (@rbuckton) may want to review the changes.

@DanielRosenwasser

Daniel Rosenwasser (DanielRosenwasser) commented Jul 31, 2017 •

Copy link
Copy Markdown
Member

(Also, thanks for the PR Tingan Ho (@tinganho), long time no see! 😄)

Comment thread src/compiler/binder.ts Outdated
if (!node.variableDeclaration) {
transformFlags |= TransformFlags.AssertESNext;
}
else if (/* node.variableDeclaration && */ isBindingPattern(node.variableDeclaration.name)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is unnecessary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

Comment thread src/compiler/checker.ts Outdated
else if (/* !catchClause.variableDeclaration && */ languageVersion < ScriptTarget.ESNext) {
const blockLocals = catchClause.block.locals;
if (blockLocals) {
forEachKey(blockLocals, caughtName => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a name? We can generate a name in the transforms.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this block of change. Since we don't need check and error on a named variable anymore.

Comment thread src/compiler/transformers/es2015.ts Outdated
const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
let updated: CatchClause;
if (isBindingPattern(node.variableDeclaration.name)) {
if (node.variableDeclaration && isBindingPattern(node.variableDeclaration.name)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the time we get to the es2015 transform we must already have a variableDeclaration. Filling in the missing binding should be handled in the esnext transform. At best we should have a debug assertion.

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Aug 1, 2017 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed!

Debug.assert(!!node.variableDeclaration, "Catch clauses should always be present when downleveling ES2015 code.");

Comment thread src/compiler/transformers/esnext.ts Outdated

function visitCatchClause(node: CatchClause): CatchClause {
if (!node.variableDeclaration) {
return updateCatchClause(node, createVariableDeclaration("_ignoredCatchParameter"), node.block);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you should either use createUniqueName or createTempVariable.

Comment thread src/compiler/types.ts Outdated
kind: SyntaxKind.CatchClause;
parent?: TryStatement;
variableDeclaration: VariableDeclaration;
parent?: TryStatement; // We parse missing try statements

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this comment mean? This property is present to reduce costs when walking up the AST.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't apparent to me that the parent can be missing in a catch clause.

@DanielRosenwasser

Daniel Rosenwasser (DanielRosenwasser) commented Aug 1, 2017 •

Copy link
Copy Markdown
Member

Sounds like you want createTempVariable, not createUniqueName (unless you have useful text in mind, but I'd keep it as short as possible). Is that accurate Ron Buckton (@rbuckton)?

@rbuckton

Copy link
Copy Markdown
Contributor

Yes, specifically createTempVariable(undefined).

@tinganho

Copy link
Copy Markdown
Contributor Author

(Thanks Daniel Rosenwasser (@DanielRosenwasser) , I have been quite busy for a while, so I haven't have time to participate so much here. Though, working with TS projects all day 😄 )

@tinganho

Copy link
Copy Markdown
Contributor Author

I now, removed the named variable ignoredCatchParameter, it made more sense to make the suggested temporary unique variable. So I cleaned up diagnostics, tests and some other unnecessary stuff.

@weswigham Wesley Wigham (weswigham) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also bemoan apparently having no coverage in the conformance suite for

try {} catch() {}

which is an error both before and after this change.

Comment thread src/compiler/transformers/esnext.ts Outdated

function visitCatchClause(node: CatchClause): CatchClause {
if (!node.variableDeclaration) {
return updateCatchClause(node, createVariableDeclaration(createTempVariable(/*recordTempVariable*/ undefined)), node.block);

@weswigham Wesley Wigham (weswigham) Aug 1, 2017 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node.block still needs to be recursively visited here, no?

function* doFoo(foo: any) {
  try {
     throw "whatever";
  }
  catch {
    try {
       throw "again"
    }
    catch {
      for await (const c of foo) {
        c;
      }
    }
  }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wesley Wigham (@weswigham) is correct, you should recursively visit the block of the catch clause.

@tinganho

Copy link
Copy Markdown
Contributor Author

Wesley Wigham (@weswigham) I think I know why, it messes up checking with the lines after it:

screen shot 2017-08-02 at 11 14 51

@tinganho

Copy link
Copy Markdown
Contributor Author

I updated the code with recursive visits.

Comment thread src/compiler/emitter.ts Outdated
if (node.variableDeclaration) {
writeToken(SyntaxKind.OpenParenToken, openParenPos);
emit(node.variableDeclaration);
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional on this line is no longer required since you are checking node.variableDeclaration on 2134.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

Comment thread src/compiler/parser.ts
if (parseExpected(SyntaxKind.OpenParenToken)) {

if (parseOptional(SyntaxKind.OpenParenToken)) {
result.variableDeclaration = parseVariableDeclaration();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conditionally setting result.variableDeclaration introduces polymorphism as we now have two CatchClause shapes, one with the property and one without. This can cause performance degradation in V8 (NodeJS). I would recommend you add an else clause that sets result.variableDeclaration = undefined to keep the shape of CatchClause the same regardless of which form the user writes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

Comment thread src/compiler/transformers/es2015.ts Outdated
function visitCatchClause(node: CatchClause): CatchClause {
const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
let updated: CatchClause;
Debug.assert(!!node.variableDeclaration, "Catch clauses should always be present when downleveling ES2015 code.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about "Catch clause variable should always be present when downleveling ES2015"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

Comment thread src/compiler/types.ts Outdated
kind: SyntaxKind.CatchClause;
parent?: TryStatement;
variableDeclaration: VariableDeclaration;
parent?: TryStatement; // We make this optional to parse missing try statements

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is unnecessary. We only re-introduce parent here to refine its type for methods in the checker. parent is optional because it parent pointers are not always set, especially during tree transformations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

Comment thread src/compiler/types.ts
parent?: TryStatement;
variableDeclaration: VariableDeclaration;
parent?: TryStatement; // We make this optional to parse missing try statements
variableDeclaration?: VariableDeclaration;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update createCatchClause and updateCatchClause in factory.ts and add | undefined to the variableDeclaration parameters in both cases? This is needed for those using the Compiler API with -strictNullChecks enabled for their project.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

@rbuckton

Copy link
Copy Markdown
Contributor

Wesley Wigham (@weswigham) I think I know why, it messes up checking with the lines after it:

screen shot 2017-08-02 at 11 14 51

invalidTryStatements.ts covers grammar errors handled in the checker. invalidTryStatements2.ts covers parse errors. I think invalidTryStatements2.ts is a better place for try {} catch () {}.

@tinganho

Tingan Ho (tinganho) commented Aug 2, 2017 •

Copy link
Copy Markdown
Contributor Author

invalidTryStatements.ts covers grammar errors handled in the checker. invalidTryStatements2.ts covers parse errors. I think invalidTryStatements2.ts is a better place for try {} catch () {}.

I added both the test cases try { } and try { } catch() { } in invalidTryStatements2.ts.

@rbuckton

Copy link
Copy Markdown
Contributor

Looks great! Thanks for the contribution!

@rbuckton
Ron Buckton (rbuckton) merged commit 75c8ecb into microsoft:master Aug 8, 2017
@tinganho

Copy link
Copy Markdown
Contributor Author

Thanks for the great review!

@microsoft Microsoft (microsoft) locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants