Skip to content

Commit

Permalink
Don't treat an instantiation expression as an assertion in skipOuterE…
Browse files Browse the repository at this point in the history
…xpressions (#59538)
  • Loading branch information
jakebailey committed Aug 6, 2024
1 parent a745d1b commit 9987812
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6553,6 +6553,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
return updateSatisfiesExpression(outerExpression, expression, outerExpression.type);
case SyntaxKind.NonNullExpression:
return updateNonNullExpression(outerExpression, expression);
case SyntaxKind.ExpressionWithTypeArguments:
return updateExpressionWithTypeArguments(outerExpression, expression, outerExpression.typeArguments);
case SyntaxKind.PartiallyEmittedExpression:
return updatePartiallyEmittedExpression(outerExpression, expression);
}
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/factory/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,10 @@ export function isOuterExpression(node: Node, kinds = OuterExpressionKinds.All):
return (kinds & OuterExpressionKinds.Parentheses) !== 0;
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.ExpressionWithTypeArguments:
case SyntaxKind.SatisfiesExpression:
return (kinds & OuterExpressionKinds.TypeAssertions) !== 0;
case SyntaxKind.ExpressionWithTypeArguments:
return (kinds & OuterExpressionKinds.ExpressionsWithTypeArguments) !== 0;
case SyntaxKind.NonNullExpression:
return (kinds & OuterExpressionKinds.NonNullAssertions) !== 0;
case SyntaxKind.PartiallyEmittedExpression:
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1689,7 +1689,7 @@ export function transformTypeScript(context: TransformationContext) {
}

function visitParenthesizedExpression(node: ParenthesizedExpression): Expression {
const innerExpression = skipOuterExpressions(node.expression, ~OuterExpressionKinds.Assertions);
const innerExpression = skipOuterExpressions(node.expression, ~(OuterExpressionKinds.Assertions | OuterExpressionKinds.ExpressionsWithTypeArguments));
if (isAssertionExpression(innerExpression) || isSatisfiesExpression(innerExpression)) {
// Make sure we consider all nested cast expressions, e.g.:
// (<any><number><any>-A).x;
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8476,11 +8476,12 @@ export const enum OuterExpressionKinds {
TypeAssertions = 1 << 1,
NonNullAssertions = 1 << 2,
PartiallyEmittedExpressions = 1 << 3,
ExpressionsWithTypeArguments = 1 << 4,

Assertions = TypeAssertions | NonNullAssertions,
All = Parentheses | Assertions | PartiallyEmittedExpressions,
All = Parentheses | Assertions | PartiallyEmittedExpressions | ExpressionsWithTypeArguments,

ExcludeJSDocTypeAssertion = 1 << 4,
ExcludeJSDocTypeAssertion = 1 << 31,
}

/** @internal */
Expand All @@ -8490,6 +8491,7 @@ export type OuterExpression =
| SatisfiesExpression
| AsExpression
| NonNullExpression
| ExpressionWithTypeArguments
| PartiallyEmittedExpression;

/** @internal */
Expand Down
5 changes: 3 additions & 2 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7346,9 +7346,10 @@ declare namespace ts {
TypeAssertions = 2,
NonNullAssertions = 4,
PartiallyEmittedExpressions = 8,
ExpressionsWithTypeArguments = 16,
Assertions = 6,
All = 15,
ExcludeJSDocTypeAssertion = 16,
All = 31,
ExcludeJSDocTypeAssertion = -2147483648,
}
type ImmediatelyInvokedFunctionExpression = CallExpression & {
readonly expression: FunctionExpression;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
assignmentToInstantiationExpression.ts(2,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access.
assignmentToInstantiationExpression.ts(6,1): error TS2454: Variable 'getValue' is used before being assigned.
assignmentToInstantiationExpression.ts(6,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access.
assignmentToInstantiationExpression.ts(10,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access.


==== assignmentToInstantiationExpression.ts (4 errors) ====
let obj: { fn?: <T>() => T } = {};
obj.fn<number> = () => 1234;
~~~~~~~~~~~~~~
!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access.


let getValue: <T>() => T;
getValue<number> = () => 1234;
~~~~~~~~
!!! error TS2454: Variable 'getValue' is used before being assigned.
~~~~~~~~~~~~~~~~
!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access.


let getValue2!: <T>() => T;
getValue2<number> = () => 1234;
~~~~~~~~~~~~~~~~~
!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access.

23 changes: 23 additions & 0 deletions tests/baselines/reference/assignmentToInstantiationExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//// [tests/cases/compiler/assignmentToInstantiationExpression.ts] ////

//// [assignmentToInstantiationExpression.ts]
let obj: { fn?: <T>() => T } = {};
obj.fn<number> = () => 1234;


let getValue: <T>() => T;
getValue<number> = () => 1234;


let getValue2!: <T>() => T;
getValue2<number> = () => 1234;


//// [assignmentToInstantiationExpression.js]
"use strict";
var obj = {};
(obj.fn) = function () { return 1234; };
var getValue;
(getValue) = function () { return 1234; };
var getValue2;
(getValue2) = function () { return 1234; };
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//// [tests/cases/compiler/assignmentToInstantiationExpression.ts] ////

=== assignmentToInstantiationExpression.ts ===
let obj: { fn?: <T>() => T } = {};
>obj : Symbol(obj, Decl(assignmentToInstantiationExpression.ts, 0, 3))
>fn : Symbol(fn, Decl(assignmentToInstantiationExpression.ts, 0, 10))
>T : Symbol(T, Decl(assignmentToInstantiationExpression.ts, 0, 17))
>T : Symbol(T, Decl(assignmentToInstantiationExpression.ts, 0, 17))

obj.fn<number> = () => 1234;
>obj.fn : Symbol(fn, Decl(assignmentToInstantiationExpression.ts, 0, 10))
>obj : Symbol(obj, Decl(assignmentToInstantiationExpression.ts, 0, 3))
>fn : Symbol(fn, Decl(assignmentToInstantiationExpression.ts, 0, 10))


let getValue: <T>() => T;
>getValue : Symbol(getValue, Decl(assignmentToInstantiationExpression.ts, 4, 3))
>T : Symbol(T, Decl(assignmentToInstantiationExpression.ts, 4, 15))
>T : Symbol(T, Decl(assignmentToInstantiationExpression.ts, 4, 15))

getValue<number> = () => 1234;
>getValue : Symbol(getValue, Decl(assignmentToInstantiationExpression.ts, 4, 3))


let getValue2!: <T>() => T;
>getValue2 : Symbol(getValue2, Decl(assignmentToInstantiationExpression.ts, 8, 3))
>T : Symbol(T, Decl(assignmentToInstantiationExpression.ts, 8, 17))
>T : Symbol(T, Decl(assignmentToInstantiationExpression.ts, 8, 17))

getValue2<number> = () => 1234;
>getValue2 : Symbol(getValue2, Decl(assignmentToInstantiationExpression.ts, 8, 3))

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//// [tests/cases/compiler/assignmentToInstantiationExpression.ts] ////

=== assignmentToInstantiationExpression.ts ===
let obj: { fn?: <T>() => T } = {};
>obj : { fn?: <T>() => T; }
> : ^^^^^^^ ^^^
>fn : (<T>() => T) | undefined
> : ^^ ^^^^^^^ ^^^^^^^^^^^^^
>{} : {}
> : ^^

obj.fn<number> = () => 1234;
>obj.fn<number> = () => 1234 : () => number
> : ^^^^^^^^^^^^
>obj.fn<number> : (() => number) | undefined
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^
>obj.fn : (<T>() => T) | undefined
> : ^^ ^^^^^^^ ^^^^^^^^^^^^^
>obj : { fn?: <T>() => T; }
> : ^^^^^^^ ^^^
>fn : (<T>() => T) | undefined
> : ^^ ^^^^^^^ ^^^^^^^^^^^^^
>() => 1234 : () => number
> : ^^^^^^^^^^^^
>1234 : 1234
> : ^^^^


let getValue: <T>() => T;
>getValue : <T>() => T
> : ^ ^^^^^^^

getValue<number> = () => 1234;
>getValue<number> = () => 1234 : () => number
> : ^^^^^^^^^^^^
>getValue<number> : () => number
> : ^^^^^^^^^^^^
>getValue : <T>() => T
> : ^ ^^^^^^^
>() => 1234 : () => number
> : ^^^^^^^^^^^^
>1234 : 1234
> : ^^^^


let getValue2!: <T>() => T;
>getValue2 : <T>() => T
> : ^ ^^^^^^^

getValue2<number> = () => 1234;
>getValue2<number> = () => 1234 : () => number
> : ^^^^^^^^^^^^
>getValue2<number> : () => number
> : ^^^^^^^^^^^^
>getValue2 : <T>() => T
> : ^ ^^^^^^^
>() => 1234 : () => number
> : ^^^^^^^^^^^^
>1234 : 1234
> : ^^^^

12 changes: 12 additions & 0 deletions tests/cases/compiler/assignmentToInstantiationExpression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @strict: true

let obj: { fn?: <T>() => T } = {};
obj.fn<number> = () => 1234;


let getValue: <T>() => T;
getValue<number> = () => 1234;


let getValue2!: <T>() => T;
getValue2<number> = () => 1234;

0 comments on commit 9987812

Please sign in to comment.