Don't emit a return statement at the end in most useful cases.

This commit is contained in:
Daniel Rosenwasser
2016-09-03 01:10:38 -07:00
parent 1be4cee0c6
commit c87a773a46

View File

@@ -804,7 +804,9 @@ namespace ts {
addRange(statements, body);
}
if (extendsClauseElement) {
// Return `_this` unless we're sure enough that it would be pointless to add a return statement.
// If there's a constructor that we can tell returns in enough places, then we *do not* want to add a return.
if (extendsClauseElement && !(constructor && isSufficientlyCoveredByReturnStatements(constructor.body))) {
statements.push(
createReturn(
createIdentifier("_this")
@@ -833,6 +835,36 @@ namespace ts {
return constructor => visitNodes(constructor.body.statements, visitor, isStatement, /*start*/ offset);
}
/**
* We want to try to avoid emitting a return statement in certain cases if a user already returned something.
* It would be pointless and generate dead code, so we'll try to make things a little bit prettier
* by doing a minimal check on whether some common patterns always explicitly return.
*/
function isSufficientlyCoveredByReturnStatements(statement: Statement): boolean {
// A return statement is considered covered.
if (statement.kind === SyntaxKind.ReturnStatement) {
return true;
}
// An if-statement with two covered branches is covered.
else if (statement.kind === SyntaxKind.IfStatement) {
const ifStatement = statement as IfStatement;
if (ifStatement.elseStatement) {
return isSufficientlyCoveredByReturnStatements(ifStatement.thenStatement) &&
isSufficientlyCoveredByReturnStatements(ifStatement.elseStatement);
}
}
// A block is covered if it has a last statement which is covered.
else if (statement.kind === SyntaxKind.Block) {
const lastStatement = lastOrUndefined((statement as Block).statements);
if (lastStatement && isSufficientlyCoveredByReturnStatements(lastStatement)) {
return true;
}
}
return false;
}
/**
* Adds a synthesized call to `_super` if it is needed.
*