From 892568983dd717872223aedad3d81c4dfa627899 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 11 Jun 2023 07:02:53 +0800 Subject: [PATCH] Add check for reference-compared literals to JS files --- src/compiler/checker.ts | 6 +++++- src/compiler/program.ts | 2 ++ .../reference/plainJSTypeErrors.errors.txt | 12 ++++++++++++ tests/baselines/reference/plainJSTypeErrors.js | 15 +++++++++++++++ .../baselines/reference/plainJSTypeErrors.symbols | 10 ++++++++++ tests/baselines/reference/plainJSTypeErrors.types | 15 +++++++++++++++ .../cases/conformance/salsa/plainJSTypeErrors.ts | 10 ++++++++++ 7 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/plainJSTypeErrors.errors.txt create mode 100644 tests/baselines/reference/plainJSTypeErrors.js create mode 100644 tests/baselines/reference/plainJSTypeErrors.symbols create mode 100644 tests/baselines/reference/plainJSTypeErrors.types create mode 100644 tests/cases/conformance/salsa/plainJSTypeErrors.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8e148c857e86e..9467a47cda0de 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -37028,7 +37028,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // control flow analysis it is possible for operands to temporarily have narrower types, and those narrower // types may cause the operands to not be comparable. We don't want such errors reported (see #46475). if (!(checkMode && checkMode & CheckMode.TypeOnly)) { - if (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) { + if ( + (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) && + // only report for === and !== in JS, not == or != + (!isInJSFile(left) || (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) + ) { const eqType = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; error(errorNode, Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, eqType ? "false" : "true"); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 345ff985a6baa..af9dcdf04c617 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1430,6 +1430,8 @@ export const plainJSErrors: Set = new Set([ Diagnostics.Class_constructor_may_not_be_a_generator.code, Diagnostics.Class_constructor_may_not_be_an_accessor.code, Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code, + // Type errors + Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value.code, ]); /** diff --git a/tests/baselines/reference/plainJSTypeErrors.errors.txt b/tests/baselines/reference/plainJSTypeErrors.errors.txt new file mode 100644 index 0000000000000..8bddc133b6159 --- /dev/null +++ b/tests/baselines/reference/plainJSTypeErrors.errors.txt @@ -0,0 +1,12 @@ +plainJSTypeErrors.js(2,5): error TS2839: This condition will always return 'false' since JavaScript compares objects by reference, not value. + + +==== plainJSTypeErrors.js (1 errors) ==== + // should error + if ({} === {}) {} + ~~~~~~~~~ +!!! error TS2839: This condition will always return 'false' since JavaScript compares objects by reference, not value. + + // should not error + if ({} == {}) {} + \ No newline at end of file diff --git a/tests/baselines/reference/plainJSTypeErrors.js b/tests/baselines/reference/plainJSTypeErrors.js new file mode 100644 index 0000000000000..9760abb049307 --- /dev/null +++ b/tests/baselines/reference/plainJSTypeErrors.js @@ -0,0 +1,15 @@ +//// [tests/cases/conformance/salsa/plainJSTypeErrors.ts] //// + +//// [plainJSTypeErrors.js] +// should error +if ({} === {}) {} + +// should not error +if ({} == {}) {} + + +//// [plainJSTypeErrors.js] +// should error +if ({} === {}) { } +// should not error +if ({} == {}) { } diff --git a/tests/baselines/reference/plainJSTypeErrors.symbols b/tests/baselines/reference/plainJSTypeErrors.symbols new file mode 100644 index 0000000000000..3d21f40c80bc9 --- /dev/null +++ b/tests/baselines/reference/plainJSTypeErrors.symbols @@ -0,0 +1,10 @@ +//// [tests/cases/conformance/salsa/plainJSTypeErrors.ts] //// + +=== plainJSTypeErrors.js === + +// should error +if ({} === {}) {} + +// should not error +if ({} == {}) {} + diff --git a/tests/baselines/reference/plainJSTypeErrors.types b/tests/baselines/reference/plainJSTypeErrors.types new file mode 100644 index 0000000000000..aa3a619cec819 --- /dev/null +++ b/tests/baselines/reference/plainJSTypeErrors.types @@ -0,0 +1,15 @@ +//// [tests/cases/conformance/salsa/plainJSTypeErrors.ts] //// + +=== plainJSTypeErrors.js === +// should error +if ({} === {}) {} +>{} === {} : boolean +>{} : {} +>{} : {} + +// should not error +if ({} == {}) {} +>{} == {} : boolean +>{} : {} +>{} : {} + diff --git a/tests/cases/conformance/salsa/plainJSTypeErrors.ts b/tests/cases/conformance/salsa/plainJSTypeErrors.ts new file mode 100644 index 0000000000000..a849e55c71fe6 --- /dev/null +++ b/tests/cases/conformance/salsa/plainJSTypeErrors.ts @@ -0,0 +1,10 @@ +// @outdir: out/ +// @target: esnext +// @allowJS: true +// @filename: plainJSTypeErrors.js + +// should error +if ({} === {}) {} + +// should not error +if ({} == {}) {}