From 214ef0c7502b6b792d45431dcb05560d8dfc303a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 3 Feb 2021 11:32:48 -0800 Subject: [PATCH 1/2] No did-you-mean-to-call error on casts I chose to do the ad-hoc check rather than yet another tree walk. 1. It's faster to run and easier to read. 2. This error came from looking at real code. It happened twice, so I think the best estimate for other uses that happened zero times is in fact zero. 3. I couldn't think of other places to put the cast, given the restrictions on `testedNode` just before the new code. --- src/compiler/checker.ts | 5 +++- .../truthinessCallExpressionCoercion3.js | 19 +++++++++++++++ .../truthinessCallExpressionCoercion3.symbols | 24 +++++++++++++++++++ .../truthinessCallExpressionCoercion3.types | 23 ++++++++++++++++++ .../truthinessCallExpressionCoercion3.ts | 13 ++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/truthinessCallExpressionCoercion3.js create mode 100644 tests/baselines/reference/truthinessCallExpressionCoercion3.symbols create mode 100644 tests/baselines/reference/truthinessCallExpressionCoercion3.types create mode 100644 tests/cases/compiler/truthinessCallExpressionCoercion3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c4b3d67ad6d96..c1c7a73c46c86 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34554,8 +34554,11 @@ namespace ts { : isPropertyAccessExpression(location) ? location.name : isBinaryExpression(location) && isIdentifier(location.right) ? location.right : undefined; + const isPropertyExpressionCast = isPropertyAccessExpression(location) + && isParenthesizedExpression(location.expression) + && isAssertionExpression(location.expression.expression); - if (!testedNode) { + if (!testedNode || isPropertyExpressionCast) { return; } diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion3.js b/tests/baselines/reference/truthinessCallExpressionCoercion3.js new file mode 100644 index 0000000000000..a2ab27f21a2ef --- /dev/null +++ b/tests/baselines/reference/truthinessCallExpressionCoercion3.js @@ -0,0 +1,19 @@ +//// [truthinessCallExpressionCoercion3.ts] +// from #41640, based on an example in ant-design +interface I { + always(): void +} + +function f(result: unknown) { + if ((result as I).always) { + return result + } +} + + +//// [truthinessCallExpressionCoercion3.js] +function f(result) { + if (result.always) { + return result; + } +} diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols b/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols new file mode 100644 index 0000000000000..35392c06aef0e --- /dev/null +++ b/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols @@ -0,0 +1,24 @@ +=== tests/cases/compiler/truthinessCallExpressionCoercion3.ts === +// from #41640, based on an example in ant-design +interface I { +>I : Symbol(I, Decl(truthinessCallExpressionCoercion3.ts, 0, 0)) + + always(): void +>always : Symbol(I.always, Decl(truthinessCallExpressionCoercion3.ts, 1, 13)) +} + +function f(result: unknown) { +>f : Symbol(f, Decl(truthinessCallExpressionCoercion3.ts, 3, 1)) +>result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 5, 11)) + + if ((result as I).always) { +>(result as I).always : Symbol(I.always, Decl(truthinessCallExpressionCoercion3.ts, 1, 13)) +>result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 5, 11)) +>I : Symbol(I, Decl(truthinessCallExpressionCoercion3.ts, 0, 0)) +>always : Symbol(I.always, Decl(truthinessCallExpressionCoercion3.ts, 1, 13)) + + return result +>result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 5, 11)) + } +} + diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion3.types b/tests/baselines/reference/truthinessCallExpressionCoercion3.types new file mode 100644 index 0000000000000..200ddbfa13ecc --- /dev/null +++ b/tests/baselines/reference/truthinessCallExpressionCoercion3.types @@ -0,0 +1,23 @@ +=== tests/cases/compiler/truthinessCallExpressionCoercion3.ts === +// from #41640, based on an example in ant-design +interface I { + always(): void +>always : () => void +} + +function f(result: unknown) { +>f : (result: unknown) => unknown +>result : unknown + + if ((result as I).always) { +>(result as I).always : () => void +>(result as I) : I +>result as I : I +>result : unknown +>always : () => void + + return result +>result : unknown + } +} + diff --git a/tests/cases/compiler/truthinessCallExpressionCoercion3.ts b/tests/cases/compiler/truthinessCallExpressionCoercion3.ts new file mode 100644 index 0000000000000..69f6ba8214d40 --- /dev/null +++ b/tests/cases/compiler/truthinessCallExpressionCoercion3.ts @@ -0,0 +1,13 @@ +// @strictNullChecks: true +// @lib: esnext,dom + +// from #41640, based on an example in ant-design +interface I { + always(): void +} + +function f(result: unknown) { + if ((result as I).always) { + return result + } +} From b3be79ad0f586073fefde73612b206eb27b427f9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 12 Feb 2021 09:38:21 -0800 Subject: [PATCH 2/2] Skip parentheses --- src/compiler/checker.ts | 4 +--- .../truthinessCallExpressionCoercion3.js | 10 ++++++++++ .../truthinessCallExpressionCoercion3.symbols | 14 ++++++++++++++ .../truthinessCallExpressionCoercion3.types | 16 ++++++++++++++++ .../truthinessCallExpressionCoercion3.ts | 5 +++++ 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a8a14dc9b66a5..b155f3dfab106 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34547,9 +34547,7 @@ namespace ts { : isBinaryExpression(location) && isIdentifier(location.right) ? location.right : undefined; const isPropertyExpressionCast = isPropertyAccessExpression(location) - && isParenthesizedExpression(location.expression) - && isAssertionExpression(location.expression.expression); - + && isAssertionExpression(skipParentheses(location.expression)); if (!testedNode || isPropertyExpressionCast) { return; } diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion3.js b/tests/baselines/reference/truthinessCallExpressionCoercion3.js index a2ab27f21a2ef..7fc1df8ffb574 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion3.js +++ b/tests/baselines/reference/truthinessCallExpressionCoercion3.js @@ -9,6 +9,11 @@ function f(result: unknown) { return result } } +function g(result: unknown) { + if (((result as I)).always) { + return result + } +} //// [truthinessCallExpressionCoercion3.js] @@ -17,3 +22,8 @@ function f(result) { return result; } } +function g(result) { + if (result.always) { + return result; + } +} diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols b/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols index 35392c06aef0e..e7ed13514df6c 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols +++ b/tests/baselines/reference/truthinessCallExpressionCoercion3.symbols @@ -21,4 +21,18 @@ function f(result: unknown) { >result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 5, 11)) } } +function g(result: unknown) { +>g : Symbol(g, Decl(truthinessCallExpressionCoercion3.ts, 9, 1)) +>result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 10, 11)) + + if (((result as I)).always) { +>((result as I)).always : Symbol(I.always, Decl(truthinessCallExpressionCoercion3.ts, 1, 13)) +>result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 10, 11)) +>I : Symbol(I, Decl(truthinessCallExpressionCoercion3.ts, 0, 0)) +>always : Symbol(I.always, Decl(truthinessCallExpressionCoercion3.ts, 1, 13)) + + return result +>result : Symbol(result, Decl(truthinessCallExpressionCoercion3.ts, 10, 11)) + } +} diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion3.types b/tests/baselines/reference/truthinessCallExpressionCoercion3.types index 200ddbfa13ecc..3d10a48a7f68e 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion3.types +++ b/tests/baselines/reference/truthinessCallExpressionCoercion3.types @@ -20,4 +20,20 @@ function f(result: unknown) { >result : unknown } } +function g(result: unknown) { +>g : (result: unknown) => unknown +>result : unknown + + if (((result as I)).always) { +>((result as I)).always : () => void +>((result as I)) : I +>(result as I) : I +>result as I : I +>result : unknown +>always : () => void + + return result +>result : unknown + } +} diff --git a/tests/cases/compiler/truthinessCallExpressionCoercion3.ts b/tests/cases/compiler/truthinessCallExpressionCoercion3.ts index 69f6ba8214d40..948e8059cf14a 100644 --- a/tests/cases/compiler/truthinessCallExpressionCoercion3.ts +++ b/tests/cases/compiler/truthinessCallExpressionCoercion3.ts @@ -11,3 +11,8 @@ function f(result: unknown) { return result } } +function g(result: unknown) { + if (((result as I)).always) { + return result + } +}