diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index c90e4c71f19..8f3b15690f7 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -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); } diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 852017bd501..d6d0de9e515 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -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: diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 668da90d8e6..d2b3e1121f4 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -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.: // (-A).x; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 564fa64e129..9b0ab54b0aa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -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 */ @@ -8490,6 +8491,7 @@ export type OuterExpression = | SatisfiesExpression | AsExpression | NonNullExpression + | ExpressionWithTypeArguments | PartiallyEmittedExpression; /** @internal */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8275e422282..0e82d5ba678 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -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; diff --git a/tests/baselines/reference/assignmentToInstantiationExpression.errors.txt b/tests/baselines/reference/assignmentToInstantiationExpression.errors.txt new file mode 100644 index 00000000000..ba7138811a1 --- /dev/null +++ b/tests/baselines/reference/assignmentToInstantiationExpression.errors.txt @@ -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 } = {}; + obj.fn = () => 1234; + ~~~~~~~~~~~~~~ +!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access. + + + let getValue: () => T; + getValue = () => 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; + getValue2 = () => 1234; + ~~~~~~~~~~~~~~~~~ +!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access. + \ No newline at end of file diff --git a/tests/baselines/reference/assignmentToInstantiationExpression.js b/tests/baselines/reference/assignmentToInstantiationExpression.js new file mode 100644 index 00000000000..e9a1d61ba0f --- /dev/null +++ b/tests/baselines/reference/assignmentToInstantiationExpression.js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/assignmentToInstantiationExpression.ts] //// + +//// [assignmentToInstantiationExpression.ts] +let obj: { fn?: () => T } = {}; +obj.fn = () => 1234; + + +let getValue: () => T; +getValue = () => 1234; + + +let getValue2!: () => T; +getValue2 = () => 1234; + + +//// [assignmentToInstantiationExpression.js] +"use strict"; +var obj = {}; +(obj.fn) = function () { return 1234; }; +var getValue; +(getValue) = function () { return 1234; }; +var getValue2; +(getValue2) = function () { return 1234; }; diff --git a/tests/baselines/reference/assignmentToInstantiationExpression.symbols b/tests/baselines/reference/assignmentToInstantiationExpression.symbols new file mode 100644 index 00000000000..9a4c902040a --- /dev/null +++ b/tests/baselines/reference/assignmentToInstantiationExpression.symbols @@ -0,0 +1,32 @@ +//// [tests/cases/compiler/assignmentToInstantiationExpression.ts] //// + +=== assignmentToInstantiationExpression.ts === +let obj: { fn?: () => 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 = () => 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; +>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 = () => 1234; +>getValue : Symbol(getValue, Decl(assignmentToInstantiationExpression.ts, 4, 3)) + + +let getValue2!: () => 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 = () => 1234; +>getValue2 : Symbol(getValue2, Decl(assignmentToInstantiationExpression.ts, 8, 3)) + diff --git a/tests/baselines/reference/assignmentToInstantiationExpression.types b/tests/baselines/reference/assignmentToInstantiationExpression.types new file mode 100644 index 00000000000..76db87269b4 --- /dev/null +++ b/tests/baselines/reference/assignmentToInstantiationExpression.types @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/assignmentToInstantiationExpression.ts] //// + +=== assignmentToInstantiationExpression.ts === +let obj: { fn?: () => T } = {}; +>obj : { fn?: () => T; } +> : ^^^^^^^ ^^^ +>fn : (() => T) | undefined +> : ^^ ^^^^^^^ ^^^^^^^^^^^^^ +>{} : {} +> : ^^ + +obj.fn = () => 1234; +>obj.fn = () => 1234 : () => number +> : ^^^^^^^^^^^^ +>obj.fn : (() => number) | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj.fn : (() => T) | undefined +> : ^^ ^^^^^^^ ^^^^^^^^^^^^^ +>obj : { fn?: () => T; } +> : ^^^^^^^ ^^^ +>fn : (() => T) | undefined +> : ^^ ^^^^^^^ ^^^^^^^^^^^^^ +>() => 1234 : () => number +> : ^^^^^^^^^^^^ +>1234 : 1234 +> : ^^^^ + + +let getValue: () => T; +>getValue : () => T +> : ^ ^^^^^^^ + +getValue = () => 1234; +>getValue = () => 1234 : () => number +> : ^^^^^^^^^^^^ +>getValue : () => number +> : ^^^^^^^^^^^^ +>getValue : () => T +> : ^ ^^^^^^^ +>() => 1234 : () => number +> : ^^^^^^^^^^^^ +>1234 : 1234 +> : ^^^^ + + +let getValue2!: () => T; +>getValue2 : () => T +> : ^ ^^^^^^^ + +getValue2 = () => 1234; +>getValue2 = () => 1234 : () => number +> : ^^^^^^^^^^^^ +>getValue2 : () => number +> : ^^^^^^^^^^^^ +>getValue2 : () => T +> : ^ ^^^^^^^ +>() => 1234 : () => number +> : ^^^^^^^^^^^^ +>1234 : 1234 +> : ^^^^ + diff --git a/tests/cases/compiler/assignmentToInstantiationExpression.ts b/tests/cases/compiler/assignmentToInstantiationExpression.ts new file mode 100644 index 00000000000..1ebf1f4fbce --- /dev/null +++ b/tests/cases/compiler/assignmentToInstantiationExpression.ts @@ -0,0 +1,12 @@ +// @strict: true + +let obj: { fn?: () => T } = {}; +obj.fn = () => 1234; + + +let getValue: () => T; +getValue = () => 1234; + + +let getValue2!: () => T; +getValue2 = () => 1234;