Revert "Revert "feat(40197): handle uncalled function checks in binary expressions (#40260)"" (#41462)
This reverts commit cf3e28ea66
.
This commit is contained in:
parent
06a2210eb5
commit
64be2a8d16
|
@ -670,7 +670,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
// We create a return control flow graph for IIFEs and constructors. For constructors
|
// We create a return control flow graph for IIFEs and constructors. For constructors
|
||||||
// we use the return control flow graph in strict property initialization checks.
|
// we use the return control flow graph in strict property initialization checks.
|
||||||
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || (isInJSFile && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
|
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
|
||||||
currentExceptionTarget = undefined;
|
currentExceptionTarget = undefined;
|
||||||
currentBreakTarget = undefined;
|
currentBreakTarget = undefined;
|
||||||
currentContinueTarget = undefined;
|
currentContinueTarget = undefined;
|
||||||
|
@ -691,7 +691,7 @@ namespace ts {
|
||||||
if (currentReturnTarget) {
|
if (currentReturnTarget) {
|
||||||
addAntecedent(currentReturnTarget, currentFlow);
|
addAntecedent(currentReturnTarget, currentFlow);
|
||||||
currentFlow = finishFlowLabel(currentReturnTarget);
|
currentFlow = finishFlowLabel(currentReturnTarget);
|
||||||
if (node.kind === SyntaxKind.Constructor || (isInJSFile && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
|
if (node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
|
||||||
(<FunctionLikeDeclaration>node).returnFlowNode = currentFlow;
|
(<FunctionLikeDeclaration>node).returnFlowNode = currentFlow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30156,6 +30156,9 @@ namespace ts {
|
||||||
workStacks.leftType[stackIndex] = leftType;
|
workStacks.leftType[stackIndex] = leftType;
|
||||||
const operator = node.operatorToken.kind;
|
const operator = node.operatorToken.kind;
|
||||||
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) {
|
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) {
|
||||||
|
if (operator === SyntaxKind.AmpersandAmpersandToken) {
|
||||||
|
checkTestingKnownTruthyCallableType(node.left, leftType);
|
||||||
|
}
|
||||||
checkTruthinessOfType(leftType, node.left);
|
checkTruthinessOfType(leftType, node.left);
|
||||||
}
|
}
|
||||||
advanceState(CheckBinaryExpressionState.FinishCheck);
|
advanceState(CheckBinaryExpressionState.FinishCheck);
|
||||||
|
@ -30689,7 +30692,7 @@ namespace ts {
|
||||||
|
|
||||||
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
|
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
|
||||||
const type = checkTruthinessExpression(node.condition);
|
const type = checkTruthinessExpression(node.condition);
|
||||||
checkTestingKnownTruthyCallableType(node.condition, node.whenTrue, type);
|
checkTestingKnownTruthyCallableType(node.condition, type, node.whenTrue);
|
||||||
const type1 = checkExpression(node.whenTrue, checkMode);
|
const type1 = checkExpression(node.whenTrue, checkMode);
|
||||||
const type2 = checkExpression(node.whenFalse, checkMode);
|
const type2 = checkExpression(node.whenFalse, checkMode);
|
||||||
return getUnionType([type1, type2], UnionReduction.Subtype);
|
return getUnionType([type1, type2], UnionReduction.Subtype);
|
||||||
|
@ -33926,7 +33929,7 @@ namespace ts {
|
||||||
// Grammar checking
|
// Grammar checking
|
||||||
checkGrammarStatementInAmbientContext(node);
|
checkGrammarStatementInAmbientContext(node);
|
||||||
const type = checkTruthinessExpression(node.expression);
|
const type = checkTruthinessExpression(node.expression);
|
||||||
checkTestingKnownTruthyCallableType(node.expression, node.thenStatement, type);
|
checkTestingKnownTruthyCallableType(node.expression, type, node.thenStatement);
|
||||||
checkSourceElement(node.thenStatement);
|
checkSourceElement(node.thenStatement);
|
||||||
|
|
||||||
if (node.thenStatement.kind === SyntaxKind.EmptyStatement) {
|
if (node.thenStatement.kind === SyntaxKind.EmptyStatement) {
|
||||||
|
@ -33936,16 +33939,16 @@ namespace ts {
|
||||||
checkSourceElement(node.elseStatement);
|
checkSourceElement(node.elseStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTestingKnownTruthyCallableType(condExpr: Expression, body: Statement | Expression, type: Type) {
|
function checkTestingKnownTruthyCallableType(condExpr: Expression, type: Type, body?: Statement | Expression) {
|
||||||
if (!strictNullChecks) {
|
if (!strictNullChecks) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const testedNode = isIdentifier(condExpr)
|
const location = isBinaryExpression(condExpr) ? condExpr.right : condExpr;
|
||||||
? condExpr
|
const testedNode = isIdentifier(location) ? location
|
||||||
: isPropertyAccessExpression(condExpr)
|
: isPropertyAccessExpression(location) ? location.name
|
||||||
? condExpr.name
|
: isBinaryExpression(location) && isIdentifier(location.right) ? location.right
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (!testedNode) {
|
if (!testedNode) {
|
||||||
return;
|
return;
|
||||||
|
@ -33966,27 +33969,34 @@ namespace ts {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const testedFunctionSymbol = getSymbolAtLocation(testedNode);
|
const testedSymbol = getSymbolAtLocation(testedNode);
|
||||||
if (!testedFunctionSymbol) {
|
if (!testedSymbol) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const functionIsUsedInBody = forEachChild(body, function check(childNode): boolean | undefined {
|
const isUsed = isBinaryExpression(condExpr.parent) ? isFunctionUsedInBinaryExpressionChain(condExpr.parent, testedSymbol)
|
||||||
|
: body ? isFunctionUsedInConditionBody(condExpr, body, testedNode, testedSymbol)
|
||||||
|
: false;
|
||||||
|
if (!isUsed) {
|
||||||
|
error(location, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFunctionUsedInConditionBody(expr: Expression, body: Statement | Expression, testedNode: Node, testedSymbol: Symbol): boolean {
|
||||||
|
return !!forEachChild(body, function check(childNode): boolean | undefined {
|
||||||
if (isIdentifier(childNode)) {
|
if (isIdentifier(childNode)) {
|
||||||
const childSymbol = getSymbolAtLocation(childNode);
|
const childSymbol = getSymbolAtLocation(childNode);
|
||||||
if (childSymbol && childSymbol === testedFunctionSymbol) {
|
if (childSymbol && childSymbol === testedSymbol) {
|
||||||
// If the test was a simple identifier, the above check is sufficient
|
// If the test was a simple identifier, the above check is sufficient
|
||||||
if (isIdentifier(condExpr)) {
|
if (isIdentifier(expr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Otherwise we need to ensure the symbol is called on the same target
|
// Otherwise we need to ensure the symbol is called on the same target
|
||||||
let testedExpression = testedNode.parent;
|
let testedExpression = testedNode.parent;
|
||||||
let childExpression = childNode.parent;
|
let childExpression = childNode.parent;
|
||||||
while (testedExpression && childExpression) {
|
while (testedExpression && childExpression) {
|
||||||
|
|
||||||
if (isIdentifier(testedExpression) && isIdentifier(childExpression) ||
|
if (isIdentifier(testedExpression) && isIdentifier(childExpression) ||
|
||||||
testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword
|
testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword) {
|
||||||
) {
|
|
||||||
return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression);
|
return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34003,13 +34013,18 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return forEachChild(childNode, check);
|
return forEachChild(childNode, check);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!functionIsUsedInBody) {
|
function isFunctionUsedInBinaryExpressionChain(node: Node, testedSymbol: Symbol): boolean {
|
||||||
error(condExpr, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead);
|
while (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
|
||||||
|
if (isCallExpression(node.right) && testedSymbol === getSymbolAtLocation(node.right.expression)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
node = node.parent;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkDoStatement(node: DoStatement) {
|
function checkDoStatement(node: DoStatement) {
|
||||||
|
|
|
@ -2812,7 +2812,7 @@ namespace ts {
|
||||||
if (isSimilarNode && currentSourceFile) {
|
if (isSimilarNode && currentSourceFile) {
|
||||||
pos = skipTrivia(currentSourceFile.text, pos);
|
pos = skipTrivia(currentSourceFile.text, pos);
|
||||||
}
|
}
|
||||||
if (emitLeadingCommentsOfPosition && isSimilarNode && contextNode.pos !== startPos) {
|
if (isSimilarNode && contextNode.pos !== startPos) {
|
||||||
const needsIndent = indentLeading && currentSourceFile && !positionsAreOnSameLine(startPos, pos, currentSourceFile);
|
const needsIndent = indentLeading && currentSourceFile && !positionsAreOnSameLine(startPos, pos, currentSourceFile);
|
||||||
if (needsIndent) {
|
if (needsIndent) {
|
||||||
increaseIndent();
|
increaseIndent();
|
||||||
|
@ -2823,7 +2823,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos = writeTokenText(token, writer, pos);
|
pos = writeTokenText(token, writer, pos);
|
||||||
if (emitTrailingCommentsOfPosition && isSimilarNode && contextNode.end !== pos) {
|
if (isSimilarNode && contextNode.end !== pos) {
|
||||||
emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ true);
|
emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ true);
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
|
@ -3469,7 +3469,7 @@ namespace ts {
|
||||||
// "comment1" is not considered to be leading comment for node.initializer
|
// "comment1" is not considered to be leading comment for node.initializer
|
||||||
// but rather a trailing comment on the previous node.
|
// but rather a trailing comment on the previous node.
|
||||||
const initializer = node.initializer;
|
const initializer = node.initializer;
|
||||||
if (emitTrailingCommentsOfPosition && (getEmitFlags(initializer) & EmitFlags.NoLeadingComments) === 0) {
|
if ((getEmitFlags(initializer) & EmitFlags.NoLeadingComments) === 0) {
|
||||||
const commentRange = getCommentRange(initializer);
|
const commentRange = getCommentRange(initializer);
|
||||||
emitTrailingCommentsOfPosition(commentRange.pos);
|
emitTrailingCommentsOfPosition(commentRange.pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(3,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(6,10): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(30,18): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(36,46): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(47,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(50,10): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(66,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
tests/cases/compiler/truthinessCallExpressionCoercion2.ts(69,14): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/truthinessCallExpressionCoercion2.ts (8 errors) ====
|
||||||
|
function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) {
|
||||||
|
// error
|
||||||
|
required1 && console.log('required');
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && required1 && console.log('required');
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required1();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && 1 && required1();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
optional && console.log('optional');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && optional && console.log('optional');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
!!required1 && console.log('not required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1() && console.log('required call');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required2 && required1() && required2();
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && required2 && required1() && console.log('foo');
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksConsole() {
|
||||||
|
// error
|
||||||
|
typeof window !== 'undefined' && window.console &&
|
||||||
|
((window.console as any).firebug || (window.console.exception && window.console.table));
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksPropertyAccess() {
|
||||||
|
const x = {
|
||||||
|
foo: {
|
||||||
|
bar() { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
x.foo.bar && console.log('x.foo.bar');
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && x.foo.bar && console.log('x.foo.bar');
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && x.foo.bar();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && 1 && x.foo.bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
optional?: () => boolean;
|
||||||
|
required() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
test() {
|
||||||
|
// error
|
||||||
|
this.required && console.log('required');
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && this.required && console.log('required');
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead?
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && this.required();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && 1 && this.required();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && this.optional && console.log('optional');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
146
tests/baselines/reference/truthinessCallExpressionCoercion2.js
Normal file
146
tests/baselines/reference/truthinessCallExpressionCoercion2.js
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
//// [truthinessCallExpressionCoercion2.ts]
|
||||||
|
function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) {
|
||||||
|
// error
|
||||||
|
required1 && console.log('required');
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && required1 && console.log('required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required1();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && 1 && required1();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
optional && console.log('optional');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && optional && console.log('optional');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
!!required1 && console.log('not required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1() && console.log('required call');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required2 && required1() && required2();
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && required2 && required1() && console.log('foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksConsole() {
|
||||||
|
// error
|
||||||
|
typeof window !== 'undefined' && window.console &&
|
||||||
|
((window.console as any).firebug || (window.console.exception && window.console.table));
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksPropertyAccess() {
|
||||||
|
const x = {
|
||||||
|
foo: {
|
||||||
|
bar() { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
x.foo.bar && console.log('x.foo.bar');
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && x.foo.bar && console.log('x.foo.bar');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && x.foo.bar();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && 1 && x.foo.bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
optional?: () => boolean;
|
||||||
|
required() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
test() {
|
||||||
|
// error
|
||||||
|
this.required && console.log('required');
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && this.required && console.log('required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && this.required();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && 1 && this.required();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && this.optional && console.log('optional');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// [truthinessCallExpressionCoercion2.js]
|
||||||
|
function test(required1, required2, optional) {
|
||||||
|
// error
|
||||||
|
required1 && console.log('required');
|
||||||
|
// error
|
||||||
|
1 && required1 && console.log('required');
|
||||||
|
// ok
|
||||||
|
required1 && required1();
|
||||||
|
// ok
|
||||||
|
required1 && 1 && required1();
|
||||||
|
// ok
|
||||||
|
optional && console.log('optional');
|
||||||
|
// ok
|
||||||
|
1 && optional && console.log('optional');
|
||||||
|
// ok
|
||||||
|
!!required1 && console.log('not required');
|
||||||
|
// ok
|
||||||
|
required1() && console.log('required call');
|
||||||
|
// ok
|
||||||
|
required1 && required2 && required1() && required2();
|
||||||
|
// error
|
||||||
|
required1 && required2 && required1() && console.log('foo');
|
||||||
|
}
|
||||||
|
function checksConsole() {
|
||||||
|
// error
|
||||||
|
typeof window !== 'undefined' && window.console &&
|
||||||
|
(window.console.firebug || (window.console.exception && window.console.table));
|
||||||
|
}
|
||||||
|
function checksPropertyAccess() {
|
||||||
|
var x = {
|
||||||
|
foo: {
|
||||||
|
bar: function () { return true; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// error
|
||||||
|
x.foo.bar && console.log('x.foo.bar');
|
||||||
|
// error
|
||||||
|
1 && x.foo.bar && console.log('x.foo.bar');
|
||||||
|
// ok
|
||||||
|
x.foo.bar && x.foo.bar();
|
||||||
|
// ok
|
||||||
|
x.foo.bar && 1 && x.foo.bar();
|
||||||
|
}
|
||||||
|
var Foo = /** @class */ (function () {
|
||||||
|
function Foo() {
|
||||||
|
}
|
||||||
|
Foo.prototype.required = function () {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
Foo.prototype.test = function () {
|
||||||
|
// error
|
||||||
|
this.required && console.log('required');
|
||||||
|
// error
|
||||||
|
1 && this.required && console.log('required');
|
||||||
|
// ok
|
||||||
|
this.required && this.required();
|
||||||
|
// ok
|
||||||
|
this.required && 1 && this.required();
|
||||||
|
// ok
|
||||||
|
1 && this.optional && console.log('optional');
|
||||||
|
};
|
||||||
|
return Foo;
|
||||||
|
}());
|
|
@ -0,0 +1,226 @@
|
||||||
|
=== tests/cases/compiler/truthinessCallExpressionCoercion2.ts ===
|
||||||
|
function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) {
|
||||||
|
>test : Symbol(test, Decl(truthinessCallExpressionCoercion2.ts, 0, 0))
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>required2 : Symbol(required2, Decl(truthinessCallExpressionCoercion2.ts, 0, 39))
|
||||||
|
>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 0, 65))
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && console.log('required');
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && required1 && console.log('required');
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required1();
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && 1 && required1();
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
optional && console.log('optional');
|
||||||
|
>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 0, 65))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && optional && console.log('optional');
|
||||||
|
>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 0, 65))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
!!required1 && console.log('not required');
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1() && console.log('required call');
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required2 && required1() && required2();
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>required2 : Symbol(required2, Decl(truthinessCallExpressionCoercion2.ts, 0, 39))
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>required2 : Symbol(required2, Decl(truthinessCallExpressionCoercion2.ts, 0, 39))
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && required2 && required1() && console.log('foo');
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>required2 : Symbol(required2, Decl(truthinessCallExpressionCoercion2.ts, 0, 39))
|
||||||
|
>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 0, 14))
|
||||||
|
>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, --, --))
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksConsole() {
|
||||||
|
>checksConsole : Symbol(checksConsole, Decl(truthinessCallExpressionCoercion2.ts, 30, 1))
|
||||||
|
|
||||||
|
// error
|
||||||
|
typeof window !== 'undefined' && window.console &&
|
||||||
|
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window.console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
|
||||||
|
((window.console as any).firebug || (window.console.exception && window.console.table));
|
||||||
|
>window.console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window.console.exception : Symbol(Console.exception, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window.console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>exception : Symbol(Console.exception, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window.console.table : Symbol(Console.table, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window.console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||||
|
>table : Symbol(Console.table, Decl(lib.dom.d.ts, --, --))
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksPropertyAccess() {
|
||||||
|
>checksPropertyAccess : Symbol(checksPropertyAccess, Decl(truthinessCallExpressionCoercion2.ts, 36, 1))
|
||||||
|
|
||||||
|
const x = {
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
|
||||||
|
foo: {
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
|
||||||
|
bar() { return true; }
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
x.foo.bar && console.log('x.foo.bar');
|
||||||
|
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && x.foo.bar && console.log('x.foo.bar');
|
||||||
|
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && x.foo.bar();
|
||||||
|
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && 1 && x.foo.bar();
|
||||||
|
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 39, 9))
|
||||||
|
>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 39, 15))
|
||||||
|
>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 40, 14))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
>Foo : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
|
||||||
|
optional?: () => boolean;
|
||||||
|
>optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 58, 11))
|
||||||
|
|
||||||
|
required() {
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
test() {
|
||||||
|
>test : Symbol(Foo.test, Decl(truthinessCallExpressionCoercion2.ts, 62, 5))
|
||||||
|
|
||||||
|
// error
|
||||||
|
this.required && console.log('required');
|
||||||
|
>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && this.required && console.log('required');
|
||||||
|
>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>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, --, --))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && this.required();
|
||||||
|
>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && 1 && this.required();
|
||||||
|
>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 59, 29))
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && this.optional && console.log('optional');
|
||||||
|
>this.optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 58, 11))
|
||||||
|
>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 56, 1))
|
||||||
|
>optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 58, 11))
|
||||||
|
>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, --, --))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,318 @@
|
||||||
|
=== tests/cases/compiler/truthinessCallExpressionCoercion2.ts ===
|
||||||
|
function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) {
|
||||||
|
>test : (required1: () => boolean, required2: () => boolean, optional?: (() => boolean) | undefined) => void
|
||||||
|
>required1 : () => boolean
|
||||||
|
>required2 : () => boolean
|
||||||
|
>optional : (() => boolean) | undefined
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && console.log('required');
|
||||||
|
>required1 && console.log('required') : void
|
||||||
|
>required1 : () => boolean
|
||||||
|
>console.log('required') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'required' : "required"
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && required1 && console.log('required');
|
||||||
|
>1 && required1 && console.log('required') : void
|
||||||
|
>1 && required1 : () => boolean
|
||||||
|
>1 : 1
|
||||||
|
>required1 : () => boolean
|
||||||
|
>console.log('required') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'required' : "required"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required1();
|
||||||
|
>required1 && required1() : boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
>required1() : boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && 1 && required1();
|
||||||
|
>required1 && 1 && required1() : boolean
|
||||||
|
>required1 && 1 : 1
|
||||||
|
>required1 : () => boolean
|
||||||
|
>1 : 1
|
||||||
|
>required1() : boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
|
||||||
|
// ok
|
||||||
|
optional && console.log('optional');
|
||||||
|
>optional && console.log('optional') : void | undefined
|
||||||
|
>optional : (() => boolean) | undefined
|
||||||
|
>console.log('optional') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'optional' : "optional"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && optional && console.log('optional');
|
||||||
|
>1 && optional && console.log('optional') : void | undefined
|
||||||
|
>1 && optional : (() => boolean) | undefined
|
||||||
|
>1 : 1
|
||||||
|
>optional : (() => boolean) | undefined
|
||||||
|
>console.log('optional') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'optional' : "optional"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
!!required1 && console.log('not required');
|
||||||
|
>!!required1 && console.log('not required') : void
|
||||||
|
>!!required1 : true
|
||||||
|
>!required1 : false
|
||||||
|
>required1 : () => boolean
|
||||||
|
>console.log('not required') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'not required' : "not required"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1() && console.log('required call');
|
||||||
|
>required1() && console.log('required call') : false | void
|
||||||
|
>required1() : boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
>console.log('required call') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'required call' : "required call"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required2 && required1() && required2();
|
||||||
|
>required1 && required2 && required1() && required2() : boolean
|
||||||
|
>required1 && required2 && required1() : boolean
|
||||||
|
>required1 && required2 : () => boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
>required2 : () => boolean
|
||||||
|
>required1() : boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
>required2() : boolean
|
||||||
|
>required2 : () => boolean
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && required2 && required1() && console.log('foo');
|
||||||
|
>required1 && required2 && required1() && console.log('foo') : false | void
|
||||||
|
>required1 && required2 && required1() : boolean
|
||||||
|
>required1 && required2 : () => boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
>required2 : () => boolean
|
||||||
|
>required1() : boolean
|
||||||
|
>required1 : () => boolean
|
||||||
|
>console.log('foo') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'foo' : "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksConsole() {
|
||||||
|
>checksConsole : () => void
|
||||||
|
|
||||||
|
// error
|
||||||
|
typeof window !== 'undefined' && window.console &&
|
||||||
|
>typeof window !== 'undefined' && window.console && ((window.console as any).firebug || (window.console.exception && window.console.table)) : any
|
||||||
|
>typeof window !== 'undefined' && window.console : false | Console
|
||||||
|
>typeof window !== 'undefined' : boolean
|
||||||
|
>typeof window : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||||
|
>window : Window & typeof globalThis
|
||||||
|
>'undefined' : "undefined"
|
||||||
|
>window.console : Console
|
||||||
|
>window : Window & typeof globalThis
|
||||||
|
>console : Console
|
||||||
|
|
||||||
|
((window.console as any).firebug || (window.console.exception && window.console.table));
|
||||||
|
>((window.console as any).firebug || (window.console.exception && window.console.table)) : any
|
||||||
|
>(window.console as any).firebug || (window.console.exception && window.console.table) : any
|
||||||
|
>(window.console as any).firebug : any
|
||||||
|
>(window.console as any) : any
|
||||||
|
>window.console as any : any
|
||||||
|
>window.console : Console
|
||||||
|
>window : Window & typeof globalThis
|
||||||
|
>console : Console
|
||||||
|
>firebug : any
|
||||||
|
>(window.console.exception && window.console.table) : (tabularData?: any, properties?: string[] | undefined) => void
|
||||||
|
>window.console.exception && window.console.table : (tabularData?: any, properties?: string[] | undefined) => void
|
||||||
|
>window.console.exception : (message?: string | undefined, ...optionalParams: any[]) => void
|
||||||
|
>window.console : Console
|
||||||
|
>window : Window & typeof globalThis
|
||||||
|
>console : Console
|
||||||
|
>exception : (message?: string | undefined, ...optionalParams: any[]) => void
|
||||||
|
>window.console.table : (tabularData?: any, properties?: string[] | undefined) => void
|
||||||
|
>window.console : Console
|
||||||
|
>window : Window & typeof globalThis
|
||||||
|
>console : Console
|
||||||
|
>table : (tabularData?: any, properties?: string[] | undefined) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksPropertyAccess() {
|
||||||
|
>checksPropertyAccess : () => void
|
||||||
|
|
||||||
|
const x = {
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>{ foo: { bar() { return true; } } } : { foo: { bar(): boolean; }; }
|
||||||
|
|
||||||
|
foo: {
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>{ bar() { return true; } } : { bar(): boolean; }
|
||||||
|
|
||||||
|
bar() { return true; }
|
||||||
|
>bar : () => boolean
|
||||||
|
>true : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
x.foo.bar && console.log('x.foo.bar');
|
||||||
|
>x.foo.bar && console.log('x.foo.bar') : void
|
||||||
|
>x.foo.bar : () => boolean
|
||||||
|
>x.foo : { bar(): boolean; }
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>bar : () => boolean
|
||||||
|
>console.log('x.foo.bar') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'x.foo.bar' : "x.foo.bar"
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && x.foo.bar && console.log('x.foo.bar');
|
||||||
|
>1 && x.foo.bar && console.log('x.foo.bar') : void
|
||||||
|
>1 && x.foo.bar : () => boolean
|
||||||
|
>1 : 1
|
||||||
|
>x.foo.bar : () => boolean
|
||||||
|
>x.foo : { bar(): boolean; }
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>bar : () => boolean
|
||||||
|
>console.log('x.foo.bar') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'x.foo.bar' : "x.foo.bar"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && x.foo.bar();
|
||||||
|
>x.foo.bar && x.foo.bar() : boolean
|
||||||
|
>x.foo.bar : () => boolean
|
||||||
|
>x.foo : { bar(): boolean; }
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>bar : () => boolean
|
||||||
|
>x.foo.bar() : boolean
|
||||||
|
>x.foo.bar : () => boolean
|
||||||
|
>x.foo : { bar(): boolean; }
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>bar : () => boolean
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && 1 && x.foo.bar();
|
||||||
|
>x.foo.bar && 1 && x.foo.bar() : boolean
|
||||||
|
>x.foo.bar && 1 : 1
|
||||||
|
>x.foo.bar : () => boolean
|
||||||
|
>x.foo : { bar(): boolean; }
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>bar : () => boolean
|
||||||
|
>1 : 1
|
||||||
|
>x.foo.bar() : boolean
|
||||||
|
>x.foo.bar : () => boolean
|
||||||
|
>x.foo : { bar(): boolean; }
|
||||||
|
>x : { foo: { bar(): boolean; }; }
|
||||||
|
>foo : { bar(): boolean; }
|
||||||
|
>bar : () => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
>Foo : Foo
|
||||||
|
|
||||||
|
optional?: () => boolean;
|
||||||
|
>optional : (() => boolean) | undefined
|
||||||
|
|
||||||
|
required() {
|
||||||
|
>required : () => boolean
|
||||||
|
|
||||||
|
return true;
|
||||||
|
>true : true
|
||||||
|
}
|
||||||
|
test() {
|
||||||
|
>test : () => void
|
||||||
|
|
||||||
|
// error
|
||||||
|
this.required && console.log('required');
|
||||||
|
>this.required && console.log('required') : void
|
||||||
|
>this.required : () => boolean
|
||||||
|
>this : this
|
||||||
|
>required : () => boolean
|
||||||
|
>console.log('required') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'required' : "required"
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && this.required && console.log('required');
|
||||||
|
>1 && this.required && console.log('required') : void
|
||||||
|
>1 && this.required : () => boolean
|
||||||
|
>1 : 1
|
||||||
|
>this.required : () => boolean
|
||||||
|
>this : this
|
||||||
|
>required : () => boolean
|
||||||
|
>console.log('required') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'required' : "required"
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && this.required();
|
||||||
|
>this.required && this.required() : boolean
|
||||||
|
>this.required : () => boolean
|
||||||
|
>this : this
|
||||||
|
>required : () => boolean
|
||||||
|
>this.required() : boolean
|
||||||
|
>this.required : () => boolean
|
||||||
|
>this : this
|
||||||
|
>required : () => boolean
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && 1 && this.required();
|
||||||
|
>this.required && 1 && this.required() : boolean
|
||||||
|
>this.required && 1 : 1
|
||||||
|
>this.required : () => boolean
|
||||||
|
>this : this
|
||||||
|
>required : () => boolean
|
||||||
|
>1 : 1
|
||||||
|
>this.required() : boolean
|
||||||
|
>this.required : () => boolean
|
||||||
|
>this : this
|
||||||
|
>required : () => boolean
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && this.optional && console.log('optional');
|
||||||
|
>1 && this.optional && console.log('optional') : void | undefined
|
||||||
|
>1 && this.optional : (() => boolean) | undefined
|
||||||
|
>1 : 1
|
||||||
|
>this.optional : (() => boolean) | undefined
|
||||||
|
>this : this
|
||||||
|
>optional : (() => boolean) | undefined
|
||||||
|
>console.log('optional') : void
|
||||||
|
>console.log : (...data: any[]) => void
|
||||||
|
>console : Console
|
||||||
|
>log : (...data: any[]) => void
|
||||||
|
>'optional' : "optional"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
83
tests/cases/compiler/truthinessCallExpressionCoercion2.ts
Normal file
83
tests/cases/compiler/truthinessCallExpressionCoercion2.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// @strictNullChecks: true
|
||||||
|
// @lib: esnext,dom
|
||||||
|
|
||||||
|
function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) {
|
||||||
|
// error
|
||||||
|
required1 && console.log('required');
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && required1 && console.log('required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required1();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && 1 && required1();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
optional && console.log('optional');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && optional && console.log('optional');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
!!required1 && console.log('not required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1() && console.log('required call');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
required1 && required2 && required1() && required2();
|
||||||
|
|
||||||
|
// error
|
||||||
|
required1 && required2 && required1() && console.log('foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksConsole() {
|
||||||
|
// error
|
||||||
|
typeof window !== 'undefined' && window.console &&
|
||||||
|
((window.console as any).firebug || (window.console.exception && window.console.table));
|
||||||
|
}
|
||||||
|
|
||||||
|
function checksPropertyAccess() {
|
||||||
|
const x = {
|
||||||
|
foo: {
|
||||||
|
bar() { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
x.foo.bar && console.log('x.foo.bar');
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && x.foo.bar && console.log('x.foo.bar');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && x.foo.bar();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
x.foo.bar && 1 && x.foo.bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
optional?: () => boolean;
|
||||||
|
required() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
test() {
|
||||||
|
// error
|
||||||
|
this.required && console.log('required');
|
||||||
|
|
||||||
|
// error
|
||||||
|
1 && this.required && console.log('required');
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && this.required();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
this.required && 1 && this.required();
|
||||||
|
|
||||||
|
// ok
|
||||||
|
1 && this.optional && console.log('optional');
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,12 +7,14 @@
|
||||||
//// if (this.#test) {
|
//// if (this.#test) {
|
||||||
//// console.log('test')
|
//// console.log('test')
|
||||||
//// }
|
//// }
|
||||||
|
//// this.#test && console.log('test');
|
||||||
//// }
|
//// }
|
||||||
////}
|
////}
|
||||||
////
|
////
|
||||||
////function foo() {
|
////function foo() {
|
||||||
//// function test() { return Math.random() > 0.5; }
|
//// function test() { return Math.random() > 0.5; }
|
||||||
//// test ? console.log('test') : undefined;
|
//// test ? console.log('test') : undefined;
|
||||||
|
//// test && console.log('test');
|
||||||
////}
|
////}
|
||||||
////
|
////
|
||||||
////function foo() {
|
////function foo() {
|
||||||
|
@ -23,6 +25,7 @@
|
||||||
//// }
|
//// }
|
||||||
//// x.foo.bar ? console.log('test') : undefined;
|
//// x.foo.bar ? console.log('test') : undefined;
|
||||||
//// if (x.foo.bar) {}
|
//// if (x.foo.bar) {}
|
||||||
|
//// x.foo.bar && console.log('test');
|
||||||
////}
|
////}
|
||||||
|
|
||||||
verify.codeFixAll({
|
verify.codeFixAll({
|
||||||
|
@ -35,12 +38,14 @@ verify.codeFixAll({
|
||||||
if (this.#test()) {
|
if (this.#test()) {
|
||||||
console.log('test')
|
console.log('test')
|
||||||
}
|
}
|
||||||
|
this.#test() && console.log('test');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function foo() {
|
function foo() {
|
||||||
function test() { return Math.random() > 0.5; }
|
function test() { return Math.random() > 0.5; }
|
||||||
test() ? console.log('test') : undefined;
|
test() ? console.log('test') : undefined;
|
||||||
|
test() && console.log('test');
|
||||||
}
|
}
|
||||||
|
|
||||||
function foo() {
|
function foo() {
|
||||||
|
@ -51,5 +56,6 @@ function foo() {
|
||||||
}
|
}
|
||||||
x.foo.bar() ? console.log('test') : undefined;
|
x.foo.bar() ? console.log('test') : undefined;
|
||||||
if (x.foo.bar()) {}
|
if (x.foo.bar()) {}
|
||||||
|
x.foo.bar() && console.log('test');
|
||||||
}`,
|
}`,
|
||||||
});
|
});
|
||||||
|
|
19
tests/cases/fourslash/codeFixMissingCallParentheses12.ts
Normal file
19
tests/cases/fourslash/codeFixMissingCallParentheses12.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
|
||||||
|
// @strictNullChecks: true
|
||||||
|
////function foo(fn: () => boolean) {
|
||||||
|
//// fn/**/ && console.log('test');
|
||||||
|
////}
|
||||||
|
|
||||||
|
verify.codeFixAvailable([
|
||||||
|
{ description: ts.Diagnostics.Add_missing_call_parentheses.message }
|
||||||
|
]);
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Add_missing_call_parentheses.message,
|
||||||
|
index: 0,
|
||||||
|
newFileContent:
|
||||||
|
`function foo(fn: () => boolean) {
|
||||||
|
fn() && console.log('test');
|
||||||
|
}`,
|
||||||
|
});
|
21
tests/cases/fourslash/codeFixMissingCallParentheses13.ts
Normal file
21
tests/cases/fourslash/codeFixMissingCallParentheses13.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
|
||||||
|
// @strictNullChecks: true
|
||||||
|
////function foo() {
|
||||||
|
//// function test() { return Math.random() > 0.5; }
|
||||||
|
//// test/**/ && console.log('test');
|
||||||
|
////}
|
||||||
|
|
||||||
|
verify.codeFixAvailable([
|
||||||
|
{ description: ts.Diagnostics.Add_missing_call_parentheses.message }
|
||||||
|
]);
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Add_missing_call_parentheses.message,
|
||||||
|
index: 0,
|
||||||
|
newFileContent:
|
||||||
|
`function foo() {
|
||||||
|
function test() { return Math.random() > 0.5; }
|
||||||
|
test() && console.log('test');
|
||||||
|
}`,
|
||||||
|
});
|
29
tests/cases/fourslash/codeFixMissingCallParentheses14.ts
Normal file
29
tests/cases/fourslash/codeFixMissingCallParentheses14.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
|
||||||
|
// @strictNullChecks: true
|
||||||
|
////function foo() {
|
||||||
|
//// const x = {
|
||||||
|
//// foo: {
|
||||||
|
//// bar() { return true; }
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// x.foo.bar/**/ && console.log('test');
|
||||||
|
////}
|
||||||
|
|
||||||
|
verify.codeFixAvailable([
|
||||||
|
{ description: ts.Diagnostics.Add_missing_call_parentheses.message }
|
||||||
|
]);
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Add_missing_call_parentheses.message,
|
||||||
|
index: 0,
|
||||||
|
newFileContent:
|
||||||
|
`function foo() {
|
||||||
|
const x = {
|
||||||
|
foo: {
|
||||||
|
bar() { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x.foo.bar() && console.log('test');
|
||||||
|
}`,
|
||||||
|
});
|
30
tests/cases/fourslash/codeFixMissingCallParentheses15.ts
Normal file
30
tests/cases/fourslash/codeFixMissingCallParentheses15.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
|
||||||
|
// @strictNullChecks: true
|
||||||
|
////class Foo {
|
||||||
|
//// test() {
|
||||||
|
//// return true;
|
||||||
|
//// }
|
||||||
|
//// run() {
|
||||||
|
//// this.test/**/ && console.log('test');
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
|
||||||
|
verify.codeFixAvailable([
|
||||||
|
{ description: ts.Diagnostics.Add_missing_call_parentheses.message }
|
||||||
|
]);
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Add_missing_call_parentheses.message,
|
||||||
|
index: 0,
|
||||||
|
newFileContent:
|
||||||
|
`class Foo {
|
||||||
|
test() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
run() {
|
||||||
|
this.test() && console.log('test');
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
|
25
tests/cases/fourslash/codeFixMissingCallParentheses16.ts
Normal file
25
tests/cases/fourslash/codeFixMissingCallParentheses16.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
|
||||||
|
// @strictNullChecks: true
|
||||||
|
////class Foo {
|
||||||
|
//// #test = () => true;
|
||||||
|
//// run() {
|
||||||
|
//// this.#test/**/ && console.log('test');
|
||||||
|
//// }
|
||||||
|
////}
|
||||||
|
|
||||||
|
verify.codeFixAvailable([
|
||||||
|
{ description: ts.Diagnostics.Add_missing_call_parentheses.message }
|
||||||
|
]);
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Add_missing_call_parentheses.message,
|
||||||
|
index: 0,
|
||||||
|
newFileContent:
|
||||||
|
`class Foo {
|
||||||
|
#test = () => true;
|
||||||
|
run() {
|
||||||
|
this.#test() && console.log('test');
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
});
|
19
tests/cases/fourslash/codeFixMissingCallParentheses17.ts
Normal file
19
tests/cases/fourslash/codeFixMissingCallParentheses17.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
|
||||||
|
// @strictNullChecks: true
|
||||||
|
////function foo(fn: () => boolean) {
|
||||||
|
//// 1 && fn/**/ && console.log('test');
|
||||||
|
////}
|
||||||
|
|
||||||
|
verify.codeFixAvailable([
|
||||||
|
{ description: ts.Diagnostics.Add_missing_call_parentheses.message }
|
||||||
|
]);
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Add_missing_call_parentheses.message,
|
||||||
|
index: 0,
|
||||||
|
newFileContent:
|
||||||
|
`function foo(fn: () => boolean) {
|
||||||
|
1 && fn() && console.log('test');
|
||||||
|
}`,
|
||||||
|
});
|
Loading…
Reference in a new issue