Skip to content

Commit

Permalink
Fix getEffectiveCheckNode (#60309)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabritto authored Nov 6, 2024
1 parent 60dd512 commit 8d95ac5
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 8 deletions.
7 changes: 4 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,6 @@ import {
isRightSideOfQualifiedNameOrPropertyAccess,
isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName,
isSameEntityName,
isSatisfiesExpression,
isSetAccessor,
isSetAccessorDeclaration,
isShorthandAmbientModuleSymbol,
Expand Down Expand Up @@ -35356,8 +35355,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function getEffectiveCheckNode(argument: Expression): Expression {
argument = skipParentheses(argument);
return isSatisfiesExpression(argument) ? skipParentheses(argument.expression) : argument;
const flags = isInJSFile(argument)
? OuterExpressionKinds.Parentheses | OuterExpressionKinds.Satisfies | OuterExpressionKinds.ExcludeJSDocTypeAssertion
: OuterExpressionKinds.Parentheses | OuterExpressionKinds.Satisfies;
return skipOuterExpressions(argument, flags);
}

function getSignatureApplicabilityError(
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 @@ -637,8 +637,9 @@ export function isOuterExpression(node: Node, kinds: OuterExpressionKinds = Oute
return (kinds & OuterExpressionKinds.Parentheses) !== 0;
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.SatisfiesExpression:
return (kinds & OuterExpressionKinds.TypeAssertions) !== 0;
case SyntaxKind.SatisfiesExpression:
return (kinds & (OuterExpressionKinds.TypeAssertions | OuterExpressionKinds.Satisfies)) !== 0;
case SyntaxKind.ExpressionWithTypeArguments:
return (kinds & OuterExpressionKinds.ExpressionsWithTypeArguments) !== 0;
case SyntaxKind.NonNullExpression:
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8557,8 +8557,9 @@ export const enum OuterExpressionKinds {
NonNullAssertions = 1 << 2,
PartiallyEmittedExpressions = 1 << 3,
ExpressionsWithTypeArguments = 1 << 4,
Satisfies = 1 << 5,

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

ExcludeJSDocTypeAssertion = 1 << 31,
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 @@ -7434,8 +7434,9 @@ declare namespace ts {
NonNullAssertions = 4,
PartiallyEmittedExpressions = 8,
ExpressionsWithTypeArguments = 16,
Assertions = 6,
All = 31,
Satisfies = 32,
Assertions = 38,
All = 63,
ExcludeJSDocTypeAssertion = -2147483648,
}
type ImmediatelyInvokedFunctionExpression = CallExpression & {
Expand Down
26 changes: 26 additions & 0 deletions tests/baselines/reference/arrowExpressionBodyJSDoc.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
mytest.js(6,44): error TS2322: Type 'string' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'string'.
mytest.js(13,44): error TS2322: Type 'string' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'string'.


==== mytest.js (2 errors) ====
/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo1 = value => /** @type {string} */({ ...value });
~~~~~~~~~~~~~~
!!! error TS2322: Type 'string' is not assignable to type 'T'.
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'string'.

/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo2 = value => /** @type {string} */(/** @type {T} */({ ...value }));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'string' is not assignable to type 'T'.
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'string'.
23 changes: 23 additions & 0 deletions tests/baselines/reference/arrowExpressionBodyJSDoc.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//// [tests/cases/compiler/arrowExpressionBodyJSDoc.ts] ////

=== mytest.js ===
/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo1 = value => /** @type {string} */({ ...value });
>foo1 : Symbol(foo1, Decl(mytest.js, 5, 5))
>value : Symbol(value, Decl(mytest.js, 5, 12))
>value : Symbol(value, Decl(mytest.js, 5, 12))

/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo2 = value => /** @type {string} */(/** @type {T} */({ ...value }));
>foo2 : Symbol(foo2, Decl(mytest.js, 12, 5))
>value : Symbol(value, Decl(mytest.js, 12, 12))
>value : Symbol(value, Decl(mytest.js, 12, 12))

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

=== mytest.js ===
/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo1 = value => /** @type {string} */({ ...value });
>foo1 : <T>(value: T | undefined) => T
> : ^ ^^ ^^ ^^^^^
>value => /** @type {string} */({ ...value }) : <T>(value: T | undefined) => T
> : ^ ^^ ^^ ^^^^^
>value : T | undefined
> : ^^^^^^^^^^^^^
>({ ...value }) : string
> : ^^^^^^
>{ ...value } : {}
> : ^^
>value : T | undefined
> : ^^^^^^^^^^^^^

/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo2 = value => /** @type {string} */(/** @type {T} */({ ...value }));
>foo2 : <T>(value: T | undefined) => T
> : ^ ^^ ^^ ^^^^^
>value => /** @type {string} */(/** @type {T} */({ ...value })) : <T>(value: T | undefined) => T
> : ^ ^^ ^^ ^^^^^
>value : T | undefined
> : ^^^^^^^^^^^^^
>(/** @type {T} */({ ...value })) : string
> : ^^^^^^
>({ ...value }) : T
> : ^
>{ ...value } : {}
> : ^^
>value : T | undefined
> : ^^^^^^^^^^^^^

Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ typeSatisfaction_errorLocations1.ts(47,24): error TS2322: Type 'number' is not a
typeSatisfaction_errorLocations1.ts(48,21): error TS2322: Type '{ a: number; }' is not assignable to type '{ a: true; }'.
Types of property 'a' are incompatible.
Type 'number' is not assignable to type 'true'.
typeSatisfaction_errorLocations1.ts(50,23): error TS2741: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
typeSatisfaction_errorLocations1.ts(51,24): error TS2741: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.


==== typeSatisfaction_errorLocations1.ts (22 errors) ====
==== typeSatisfaction_errorLocations1.ts (24 errors) ====
const obj1 = { a: 1 };

const fn1 = (s: { a: true }) => {};
Expand Down Expand Up @@ -143,4 +145,13 @@ typeSatisfaction_errorLocations1.ts(48,21): error TS2322: Type '{ a: number; }'
!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a: true; }'.
!!! error TS2322: Types of property 'a' are incompatible.
!!! error TS2322: Type 'number' is not assignable to type 'true'.

((): { a: true } => (({}) satisfies unknown) satisfies unknown)();
~~
!!! error TS2741: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
!!! related TS2728 typeSatisfaction_errorLocations1.ts:50:8: 'a' is declared here.
((): { a: true } => ((({}) satisfies unknown)) satisfies unknown)();
~~
!!! error TS2741: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
!!! related TS2728 typeSatisfaction_errorLocations1.ts:51:8: 'a' is declared here.

Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,9 @@ function fn6(): number {
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 47, 6))
>obj1 : Symbol(obj1, Decl(typeSatisfaction_errorLocations1.ts, 0, 5))

((): { a: true } => (({}) satisfies unknown) satisfies unknown)();
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 49, 6))

((): { a: true } => ((({}) satisfies unknown)) satisfies unknown)();
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 50, 6))

46 changes: 46 additions & 0 deletions tests/baselines/reference/typeSatisfaction_errorLocations1.types
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,49 @@ function fn6(): number {
>obj1 : { a: number; }
> : ^^^^^^^^^^^^^^

((): { a: true } => (({}) satisfies unknown) satisfies unknown)();
>((): { a: true } => (({}) satisfies unknown) satisfies unknown)() : { a: true; }
> : ^^^^^ ^^^
>((): { a: true } => (({}) satisfies unknown) satisfies unknown) : () => { a: true; }
> : ^^^^^^
>(): { a: true } => (({}) satisfies unknown) satisfies unknown : () => { a: true; }
> : ^^^^^^
>a : true
> : ^^^^
>true : true
> : ^^^^
>(({}) satisfies unknown) satisfies unknown : {}
> : ^^
>(({}) satisfies unknown) : {}
> : ^^
>({}) satisfies unknown : {}
> : ^^
>({}) : {}
> : ^^
>{} : {}
> : ^^

((): { a: true } => ((({}) satisfies unknown)) satisfies unknown)();
>((): { a: true } => ((({}) satisfies unknown)) satisfies unknown)() : { a: true; }
> : ^^^^^ ^^^
>((): { a: true } => ((({}) satisfies unknown)) satisfies unknown) : () => { a: true; }
> : ^^^^^^
>(): { a: true } => ((({}) satisfies unknown)) satisfies unknown : () => { a: true; }
> : ^^^^^^
>a : true
> : ^^^^
>true : true
> : ^^^^
>((({}) satisfies unknown)) satisfies unknown : {}
> : ^^
>((({}) satisfies unknown)) : {}
> : ^^
>(({}) satisfies unknown) : {}
> : ^^
>({}) satisfies unknown : {}
> : ^^
>({}) : {}
> : ^^
>{} : {}
> : ^^

20 changes: 20 additions & 0 deletions tests/cases/compiler/arrowExpressionBodyJSDoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @strict: true
// @noEmit: true
// @checkJs: true
// @allowJs: true

// @filename: mytest.js

/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo1 = value => /** @type {string} */({ ...value });

/**
* @template T
* @param {T|undefined} value value or not
* @returns {T} result value
*/
const foo2 = value => /** @type {string} */(/** @type {T} */({ ...value }));
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ function fn6(): number {
((): { a: true } => ({}) satisfies unknown)();
((): { a: true } => ({ a: 1 }) satisfies unknown)();
((): { a: true } => obj1 satisfies unknown)();

((): { a: true } => (({}) satisfies unknown) satisfies unknown)();
((): { a: true } => ((({}) satisfies unknown)) satisfies unknown)();

0 comments on commit 8d95ac5

Please sign in to comment.