Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on syntactically impossible ===s to undefined #60433

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
@@ -40006,6 +40006,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
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");
}
const otherUndefinedOp =
(left.kind === SyntaxKind.Identifier && getSymbolAtLocation(left) === undefinedSymbol) ? right :
(right.kind === SyntaxKind.Identifier && getSymbolAtLocation(right) === undefinedSymbol) ? left : undefined;
if (otherUndefinedOp) {
if (getSyntacticNullishnessSemantics(otherUndefinedOp) !== PredicateSemantics.Sometimes) {
error(otherUndefinedOp, Diagnostics.This_binary_expression_is_never_nullish_Are_you_missing_parentheses);
}
}
checkNaNEquality(errorNode, operator, left, right);
reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left));
}
Original file line number Diff line number Diff line change
@@ -14,9 +14,13 @@ comparisonOperatorWithIdenticalPrimitiveType.ts(42,11): error TS18050: The value
comparisonOperatorWithIdenticalPrimitiveType.ts(42,19): error TS18050: The value 'null' cannot be used here.
comparisonOperatorWithIdenticalPrimitiveType.ts(43,11): error TS18050: The value 'undefined' cannot be used here.
comparisonOperatorWithIdenticalPrimitiveType.ts(43,24): error TS18050: The value 'undefined' cannot be used here.
comparisonOperatorWithIdenticalPrimitiveType.ts(52,24): error TS2870: This binary expression is never nullish. Are you missing parentheses?
comparisonOperatorWithIdenticalPrimitiveType.ts(61,24): error TS2870: This binary expression is never nullish. Are you missing parentheses?
comparisonOperatorWithIdenticalPrimitiveType.ts(70,25): error TS2870: This binary expression is never nullish. Are you missing parentheses?
comparisonOperatorWithIdenticalPrimitiveType.ts(79,25): error TS2870: This binary expression is never nullish. Are you missing parentheses?


==== comparisonOperatorWithIdenticalPrimitiveType.ts (16 errors) ====
==== comparisonOperatorWithIdenticalPrimitiveType.ts (20 errors) ====
enum E { a, b, c }

var a: number;
@@ -101,6 +105,8 @@ comparisonOperatorWithIdenticalPrimitiveType.ts(43,24): error TS18050: The value
var re5 = e == e;
var re6 = null == null;
var re7 = undefined == undefined;
~~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?

// operator !=
var rf1 = a != a;
@@ -110,6 +116,8 @@ comparisonOperatorWithIdenticalPrimitiveType.ts(43,24): error TS18050: The value
var rf5 = e != e;
var rf6 = null != null;
var rf7 = undefined != undefined;
~~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
Copy link

Choose a reason for hiding this comment

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

Why would we get this error here? Surely undefined is always nullish?

Copy link
Contributor

Choose a reason for hiding this comment

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

i mean, when it's not ES5, or not the global scope, it could be any value, but presumably TS is ignoring that possibility :-)


// operator ===
var rg1 = a === a;
@@ -119,6 +127,8 @@ comparisonOperatorWithIdenticalPrimitiveType.ts(43,24): error TS18050: The value
var rg5 = e === e;
var rg6 = null === null;
var rg7 = undefined === undefined;
~~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?

// operator !==
var rh1 = a !== a;
@@ -127,4 +137,6 @@ comparisonOperatorWithIdenticalPrimitiveType.ts(43,24): error TS18050: The value
var rh4 = d !== d;
var rh5 = e !== e;
var rh6 = null !== null;
var rh7 = undefined !== undefined;
var rh7 = undefined !== undefined;
~~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
conditionalOperatorConditionIsBooleanType.ts(36,1): error TS2870: This binary expression is never nullish. Are you missing parentheses?
conditionalOperatorConditionIsBooleanType.ts(38,1): error TS2870: This binary expression is never nullish. Are you missing parentheses?
conditionalOperatorConditionIsBooleanType.ts(59,23): error TS2870: This binary expression is never nullish. Are you missing parentheses?


==== conditionalOperatorConditionIsBooleanType.ts (3 errors) ====
//Cond ? Expr1 : Expr2, Cond is of boolean type, Expr1 and Expr2 have the same type
var condBoolean: boolean;

var exprAny1: any;
var exprBoolean1: boolean;
var exprNumber1: number;
var exprString1: string;
var exprIsObject1: Object;

var exprAny2: any;
var exprBoolean2: boolean;
var exprNumber2: number;
var exprString2: string;
var exprIsObject2: Object;

//Cond is a boolean type variable
condBoolean ? exprAny1 : exprAny2;
condBoolean ? exprBoolean1 : exprBoolean2;
condBoolean ? exprNumber1 : exprNumber2;
condBoolean ? exprString1 : exprString2;
condBoolean ? exprIsObject1 : exprIsObject2;
condBoolean ? exprString1 : exprBoolean1; // union

//Cond is a boolean type literal
true ? exprAny1 : exprAny2;
false ? exprBoolean1 : exprBoolean2;
true ? exprNumber1 : exprNumber2;
false ? exprString1 : exprString2;
true ? exprIsObject1 : exprIsObject2;
true ? exprString1 : exprBoolean1; // union

//Cond is a boolean type expression
!true ? exprAny1 : exprAny2;
typeof "123" == "string" ? exprBoolean1 : exprBoolean2;
2 > 1 ? exprNumber1 : exprNumber2;
null === undefined ? exprString1 : exprString2;
~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
true || false ? exprIsObject1 : exprIsObject2;
null === undefined ? exprString1 : exprBoolean1; // union
~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?

//Results shoud be same as Expr1 and Expr2
var resultIsAny1 = condBoolean ? exprAny1 : exprAny2;
var resultIsBoolean1 = condBoolean ? exprBoolean1 : exprBoolean2;
var resultIsNumber1 = condBoolean ? exprNumber1 : exprNumber2;
var resultIsString1 = condBoolean ? exprString1 : exprString2;
var resultIsObject1 = condBoolean ? exprIsObject1 : exprIsObject2;
var resultIsStringOrBoolean1 = condBoolean ? exprString1 : exprBoolean1; // union

var resultIsAny2 = true ? exprAny1 : exprAny2;
var resultIsBoolean2 = false ? exprBoolean1 : exprBoolean2;
var resultIsNumber2 = true ? exprNumber1 : exprNumber2;
var resultIsString2 = false ? exprString1 : exprString2;
var resultIsObject2 = true ? exprIsObject1 : exprIsObject2;
var resultIsStringOrBoolean2 = true ? exprString1 : exprBoolean1; // union
var resultIsStringOrBoolean3 = false ? exprString1 : exprBoolean1; // union

var resultIsAny3 = !true ? exprAny1 : exprAny2;
var resultIsBoolean3 = typeof "123" == "string" ? exprBoolean1 : exprBoolean2;
var resultIsNumber3 = 2 > 1 ? exprNumber1 : exprNumber2;
var resultIsString3 = null === undefined ? exprString1 : exprString2;
~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
var resultIsObject3 = true || false ? exprIsObject1 : exprIsObject2;
var resultIsStringOrBoolean4 = typeof "123" === "string" ? exprString1 : exprBoolean1; // union

Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ var condBoolean: boolean;

var exprAny1: any;
>exprAny1 : any
> : ^^^

var exprBoolean1: boolean;
>exprBoolean1 : boolean
@@ -27,6 +28,7 @@ var exprIsObject1: Object;

var exprAny2: any;
>exprAny2 : any
> : ^^^

var exprBoolean2: boolean;
>exprBoolean2 : boolean
@@ -47,10 +49,13 @@ var exprIsObject2: Object;
//Cond is a boolean type variable
condBoolean ? exprAny1 : exprAny2;
>condBoolean ? exprAny1 : exprAny2 : any
> : ^^^
>condBoolean : boolean
> : ^^^^^^^
>exprAny1 : any
> : ^^^
>exprAny2 : any
> : ^^^

condBoolean ? exprBoolean1 : exprBoolean2;
>condBoolean ? exprBoolean1 : exprBoolean2 : boolean
@@ -105,10 +110,13 @@ condBoolean ? exprString1 : exprBoolean1; // union
//Cond is a boolean type literal
true ? exprAny1 : exprAny2;
>true ? exprAny1 : exprAny2 : any
> : ^^^
>true : true
> : ^^^^
>exprAny1 : any
> : ^^^
>exprAny2 : any
> : ^^^

false ? exprBoolean1 : exprBoolean2;
>false ? exprBoolean1 : exprBoolean2 : boolean
@@ -163,12 +171,15 @@ true ? exprString1 : exprBoolean1; // union
//Cond is a boolean type expression
!true ? exprAny1 : exprAny2;
>!true ? exprAny1 : exprAny2 : any
> : ^^^
>!true : boolean
> : ^^^^^^^
>true : true
> : ^^^^
>exprAny1 : any
> : ^^^
>exprAny2 : any
> : ^^^

typeof "123" == "string" ? exprBoolean1 : exprBoolean2;
>typeof "123" == "string" ? exprBoolean1 : exprBoolean2 : boolean
@@ -241,11 +252,15 @@ null === undefined ? exprString1 : exprBoolean1; // union
//Results shoud be same as Expr1 and Expr2
var resultIsAny1 = condBoolean ? exprAny1 : exprAny2;
>resultIsAny1 : any
> : ^^^
>condBoolean ? exprAny1 : exprAny2 : any
> : ^^^
>condBoolean : boolean
> : ^^^^^^^
>exprAny1 : any
> : ^^^
>exprAny2 : any
> : ^^^

var resultIsBoolean1 = condBoolean ? exprBoolean1 : exprBoolean2;
>resultIsBoolean1 : boolean
@@ -309,11 +324,15 @@ var resultIsStringOrBoolean1 = condBoolean ? exprString1 : exprBoolean1; // unio

var resultIsAny2 = true ? exprAny1 : exprAny2;
>resultIsAny2 : any
> : ^^^
>true ? exprAny1 : exprAny2 : any
> : ^^^
>true : true
> : ^^^^
>exprAny1 : any
> : ^^^
>exprAny2 : any
> : ^^^

var resultIsBoolean2 = false ? exprBoolean1 : exprBoolean2;
>resultIsBoolean2 : boolean
@@ -389,13 +408,17 @@ var resultIsStringOrBoolean3 = false ? exprString1 : exprBoolean1; // union

var resultIsAny3 = !true ? exprAny1 : exprAny2;
>resultIsAny3 : any
> : ^^^
>!true ? exprAny1 : exprAny2 : any
> : ^^^
>!true : boolean
> : ^^^^^^^
>true : true
> : ^^^^
>exprAny1 : any
> : ^^^
>exprAny2 : any
> : ^^^

var resultIsBoolean3 = typeof "123" == "string" ? exprBoolean1 : exprBoolean2;
>resultIsBoolean3 : boolean
11 changes: 10 additions & 1 deletion tests/baselines/reference/equalityStrictNulls.errors.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
equalityStrictNulls.ts(37,22): error TS2870: This binary expression is never nullish. Are you missing parentheses?
equalityStrictNulls.ts(39,22): error TS2870: This binary expression is never nullish. Are you missing parentheses?
equalityStrictNulls.ts(41,9): error TS2870: This binary expression is never nullish. Are you missing parentheses?
equalityStrictNulls.ts(59,13): error TS18050: The value 'undefined' cannot be used here.
equalityStrictNulls.ts(61,13): error TS18050: The value 'undefined' cannot be used here.
equalityStrictNulls.ts(63,14): error TS18050: The value 'undefined' cannot be used here.
equalityStrictNulls.ts(65,14): error TS18050: The value 'undefined' cannot be used here.


==== equalityStrictNulls.ts (4 errors) ====
==== equalityStrictNulls.ts (7 errors) ====
function f1(x: string) {
if (x == undefined) {
}
@@ -42,10 +45,16 @@ equalityStrictNulls.ts(65,14): error TS18050: The value 'undefined' cannot be us

function f2() {
if (undefined == undefined) {
~~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
}
if (undefined == null) {
~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
}
if (null == undefined) {
~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
}
if (null == null) {
}
Original file line number Diff line number Diff line change
@@ -2,9 +2,10 @@ functionImplementationErrors.ts(25,16): error TS2355: A function whose declared
functionImplementationErrors.ts(30,17): error TS2373: Parameter 'n' cannot reference identifier 'm' declared after it.
functionImplementationErrors.ts(35,17): error TS2373: Parameter 'n' cannot reference identifier 'm' declared after it.
functionImplementationErrors.ts(40,1): error TS2839: This condition will always return 'false' since JavaScript compares objects by reference, not value.
functionImplementationErrors.ts(40,15): error TS2870: This binary expression is never nullish. Are you missing parentheses?


==== functionImplementationErrors.ts (4 errors) ====
==== functionImplementationErrors.ts (5 errors) ====
// FunctionExpression with no return type annotation with multiple return statements with unrelated types
var f1 = function () {
return '';
@@ -52,6 +53,8 @@ functionImplementationErrors.ts(40,1): error TS2839: This condition will always
// Should be error but isn't
undefined === function (): number {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
throw undefined;
~~~~~~~~~~~~~~~~~~~~
var x = 4;
5 changes: 4 additions & 1 deletion tests/baselines/reference/functionImplementations.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
functionImplementations.ts(85,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a' must be of type 'any', but here has type 'Base'.
functionImplementations.ts(90,1): error TS2839: This condition will always return 'false' since JavaScript compares objects by reference, not value.
functionImplementations.ts(90,15): error TS2870: This binary expression is never nullish. Are you missing parentheses?


==== functionImplementations.ts (2 errors) ====
==== functionImplementations.ts (3 errors) ====
// FunctionExpression with no return type annotation and no return statement returns void
var v: void = function () { } ();

@@ -97,6 +98,8 @@ functionImplementations.ts(90,1): error TS2839: This condition will always retur
// FunctionExpression with non -void return type annotation with a single throw statement
undefined === function (): number {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~
!!! error TS2870: This binary expression is never nullish. Are you missing parentheses?
throw undefined;
~~~~~~~~~~~~~~~~~~~~
};
Loading
Oops, something went wrong.