From a716293d8be70b21611643bbda8f90673223b8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 23 Mar 2023 00:05:12 +0100 Subject: [PATCH 1/3] Revert "Revert PR #51580 (#53283)" This reverts commit 7f292bf2a19aa14ed69a55e646111af9533d8f1c. --- src/compiler/checker.ts | 2 +- ...thSpreadingResultOfGenericFunction.symbols | 47 +++++++++++++++++++ ...WithSpreadingResultOfGenericFunction.types | 36 ++++++++++++++ ...ntWithSpreadingResultOfGenericFunction.tsx | 18 +++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols create mode 100644 tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types create mode 100644 tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 825d339cfd3bd..27ff7f9447a1b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30380,7 +30380,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); attributesTable = createSymbolTable(); } - const exprType = getReducedType(checkExpressionCached(attributeDecl.expression, checkMode)); + const exprType = getReducedType(checkExpression(attributeDecl.expression)); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } diff --git a/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols new file mode 100644 index 0000000000000..9a98bcaf939b1 --- /dev/null +++ b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.symbols @@ -0,0 +1,47 @@ +=== tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx === +/// + +// repro #51577 + +declare function omit(names: readonly K[], obj: T): Omit; +>omit : Symbol(omit, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 0, 0), Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 84)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 22)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 24)) +>names : Symbol(names, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 43)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 24)) +>obj : Symbol(obj, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 63)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 22)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 22)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 24)) + +declare function omit(names: readonly K[]): (obj: T) => Omit; +>omit : Symbol(omit, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 0, 0), Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 84)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 22)) +>names : Symbol(names, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 40)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 22)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 63)) +>obj : Symbol(obj, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 66)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 63)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 63)) +>K : Symbol(K, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 5, 22)) + +declare const otherProps: { bar: string, qwe: boolean } +>otherProps : Symbol(otherProps, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 13)) +>bar : Symbol(bar, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 27)) +>qwe : Symbol(qwe, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 40)) + +declare function GenericComponent(props: T): null +>GenericComponent : Symbol(GenericComponent, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 55)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 9, 34)) +>props : Symbol(props, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 9, 37)) +>T : Symbol(T, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 9, 34)) + +; // no error +>GenericComponent : Symbol(GenericComponent, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 55)) +>omit : Symbol(omit, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 0, 0), Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 4, 84)) +>otherProps : Symbol(otherProps, Decl(jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx, 7, 13)) + + + diff --git a/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types new file mode 100644 index 0000000000000..7d6093bcd9efb --- /dev/null +++ b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types @@ -0,0 +1,36 @@ +=== tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx === +/// + +// repro #51577 + +declare function omit(names: readonly K[], obj: T): Omit; +>omit : { (names: readonly K[], obj: T): Omit; (names: readonly K[]): (obj: T) => Omit; } +>names : readonly K[] +>obj : T + +declare function omit(names: readonly K[]): (obj: T) => Omit; +>omit : { (names: readonly K[], obj: T): Omit; (names: readonly K[]): (obj: T) => Omit; } +>names : readonly K[] +>obj : T + +declare const otherProps: { bar: string, qwe: boolean } +>otherProps : { bar: string; qwe: boolean; } +>bar : string +>qwe : boolean + +declare function GenericComponent(props: T): null +>GenericComponent : (props: T) => null +>props : T +>null : null + +; // no error +> : JSX.Element +>GenericComponent : (props: T) => null +>omit(['bar'], otherProps) : Omit<{ bar: string; qwe: boolean; }, "bar"> +>omit : { (names: readonly K[], obj: T): Omit; (names: readonly K[]): (obj: T) => Omit; } +>['bar'] : "bar"[] +>'bar' : "bar" +>otherProps : { bar: string; qwe: boolean; } + + + diff --git a/tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx b/tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx new file mode 100644 index 0000000000000..abb94add5e62a --- /dev/null +++ b/tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx @@ -0,0 +1,18 @@ +// @strict: true +// @noEmit: true +// @jsx: preserve + +/// + +// repro #51577 + +declare function omit(names: readonly K[], obj: T): Omit; +declare function omit(names: readonly K[]): (obj: T) => Omit; + +declare const otherProps: { bar: string, qwe: boolean } + +declare function GenericComponent(props: T): null + +; // no error + + From 7d58c7812d95516987722a6fa69185eb500b063f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 23 Mar 2023 00:12:11 +0100 Subject: [PATCH 2/3] Gather intra expression inference sites in spread expressions --- src/compiler/checker.ts | 12 +++--- .../intraExpressionInferences.errors.txt | 17 +++++++- .../reference/intraExpressionInferences.js | 39 ++++++++++++++++- .../intraExpressionInferences.symbols | 42 +++++++++++++++++++ .../reference/intraExpressionInferences.types | 42 +++++++++++++++++++ .../intraExpressionInferences.ts | 16 +++++++ 6 files changed, 160 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 27ff7f9447a1b..4a0cbc829e7d1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30008,7 +30008,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.immediateTarget; } - function checkObjectLiteral(node: ObjectLiteralExpression, checkMode?: CheckMode): Type { + function checkObjectLiteral(node: ObjectLiteralExpression, checkMode: CheckMode = CheckMode.Normal): Type { const inDestructuringPattern = isAssignmentTarget(node); // Grammar checking checkGrammarObjectLiteralExpression(node, inDestructuringPattern); @@ -30110,7 +30110,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { member = prop; allPropertiesTable?.set(prop.escapedName, prop); - if (contextualType && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && + if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context @@ -30130,7 +30130,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { hasComputedNumberProperty = false; hasComputedSymbolProperty = false; } - const type = getReducedType(checkExpression(memberDecl.expression)); + const type = getReducedType(checkExpression(memberDecl.expression, checkMode & CheckMode.Inferential)); if (isValidSpreadType(type)) { const mergedType = tryMergeUnionOfObjectTypeAndEmptyObject(type, inConstContext); if (allPropertiesTable) { @@ -30330,7 +30330,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral, * which also calls getSpreadType. */ - function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode | undefined) { + function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode = CheckMode.Normal) { const attributes = openingLikeElement.attributes; const contextualType = getContextualType(attributes, ContextFlags.None); const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined; @@ -30367,7 +30367,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); } } - if (contextualType && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) { + if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) { const inferenceContext = getInferenceContext(attributes); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!; @@ -30380,7 +30380,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); attributesTable = createSymbolTable(); } - const exprType = getReducedType(checkExpression(attributeDecl.expression)); + const exprType = getReducedType(checkExpression(attributeDecl.expression, checkMode & CheckMode.Inferential)); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } diff --git a/tests/baselines/reference/intraExpressionInferences.errors.txt b/tests/baselines/reference/intraExpressionInferences.errors.txt index 745cd9b9e426c..6dfb097b62ac6 100644 --- a/tests/baselines/reference/intraExpressionInferences.errors.txt +++ b/tests/baselines/reference/intraExpressionInferences.errors.txt @@ -212,4 +212,19 @@ tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInf let test1: "a" = u } }) - \ No newline at end of file + + interface Props { + a: (x: string) => T; + b: (arg: T) => void; + } + + declare function Foo(props: Props): null; + + Foo({ + ...{ + a: (x) => 10, + b: (arg) => { + arg.toString(); + }, + }, + }); \ No newline at end of file diff --git a/tests/baselines/reference/intraExpressionInferences.js b/tests/baselines/reference/intraExpressionInferences.js index 5392616122e7b..e8947f2fb2511 100644 --- a/tests/baselines/reference/intraExpressionInferences.js +++ b/tests/baselines/reference/intraExpressionInferences.js @@ -197,11 +197,37 @@ branch({ let test1: "a" = u } }) - + +interface Props { + a: (x: string) => T; + b: (arg: T) => void; +} + +declare function Foo(props: Props): null; + +Foo({ + ...{ + a: (x) => 10, + b: (arg) => { + arg.toString(); + }, + }, +}); //// [intraExpressionInferences.js] "use strict"; // Repros from #47599 +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; callIt({ produce: function () { return 0; }, consume: function (n) { return n.toFixed(); } @@ -316,6 +342,12 @@ branch({ var test1 = u; } }); +Foo(__assign({ + a: function (x) { return 10; }, + b: function (arg) { + arg.toString(); + }, +})); //// [intraExpressionInferences.d.ts] @@ -383,3 +415,8 @@ declare const branch: (_: { then: (u: U) => void; }) => void; declare const x: "a" | "b"; +interface Props { + a: (x: string) => T; + b: (arg: T) => void; +} +declare function Foo(props: Props): null; diff --git a/tests/baselines/reference/intraExpressionInferences.symbols b/tests/baselines/reference/intraExpressionInferences.symbols index 6651221146f12..74c294a24547b 100644 --- a/tests/baselines/reference/intraExpressionInferences.symbols +++ b/tests/baselines/reference/intraExpressionInferences.symbols @@ -626,3 +626,45 @@ branch({ } }) +interface Props { +>Props : Symbol(Props, Decl(intraExpressionInferences.ts, 197, 2)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 199, 16)) + + a: (x: string) => T; +>a : Symbol(Props.a, Decl(intraExpressionInferences.ts, 199, 20)) +>x : Symbol(x, Decl(intraExpressionInferences.ts, 200, 6)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 199, 16)) + + b: (arg: T) => void; +>b : Symbol(Props.b, Decl(intraExpressionInferences.ts, 200, 22)) +>arg : Symbol(arg, Decl(intraExpressionInferences.ts, 201, 6)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 199, 16)) +} + +declare function Foo(props: Props): null; +>Foo : Symbol(Foo, Decl(intraExpressionInferences.ts, 202, 1)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 204, 21)) +>props : Symbol(props, Decl(intraExpressionInferences.ts, 204, 24)) +>Props : Symbol(Props, Decl(intraExpressionInferences.ts, 197, 2)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 204, 21)) + +Foo({ +>Foo : Symbol(Foo, Decl(intraExpressionInferences.ts, 202, 1)) + + ...{ + a: (x) => 10, +>a : Symbol(a, Decl(intraExpressionInferences.ts, 207, 6)) +>x : Symbol(x, Decl(intraExpressionInferences.ts, 208, 8)) + + b: (arg) => { +>b : Symbol(b, Decl(intraExpressionInferences.ts, 208, 17)) +>arg : Symbol(arg, Decl(intraExpressionInferences.ts, 209, 8)) + + arg.toString(); +>arg.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>arg : Symbol(arg, Decl(intraExpressionInferences.ts, 209, 8)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + + }, + }, +}); diff --git a/tests/baselines/reference/intraExpressionInferences.types b/tests/baselines/reference/intraExpressionInferences.types index 87e12e55daef4..84da105b5c1e2 100644 --- a/tests/baselines/reference/intraExpressionInferences.types +++ b/tests/baselines/reference/intraExpressionInferences.types @@ -659,3 +659,45 @@ branch({ } }) +interface Props { + a: (x: string) => T; +>a : (x: string) => T +>x : string + + b: (arg: T) => void; +>b : (arg: T) => void +>arg : T +} + +declare function Foo(props: Props): null; +>Foo : (props: Props) => null +>props : Props + +Foo({ +>Foo({ ...{ a: (x) => 10, b: (arg) => { arg.toString(); }, },}) : null +>Foo : (props: Props) => null +>{ ...{ a: (x) => 10, b: (arg) => { arg.toString(); }, },} : { a: (x: string) => number; b: (arg: number) => void; } + + ...{ +>{ a: (x) => 10, b: (arg) => { arg.toString(); }, } : { a: (x: string) => number; b: (arg: number) => void; } + + a: (x) => 10, +>a : (x: string) => number +>(x) => 10 : (x: string) => number +>x : string +>10 : 10 + + b: (arg) => { +>b : (arg: number) => void +>(arg) => { arg.toString(); } : (arg: number) => void +>arg : number + + arg.toString(); +>arg.toString() : string +>arg.toString : (radix?: number | undefined) => string +>arg : number +>toString : (radix?: number | undefined) => string + + }, + }, +}); diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts b/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts index f79902d6ae79d..9fdbebfa028b1 100644 --- a/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts +++ b/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts @@ -199,3 +199,19 @@ branch({ let test1: "a" = u } }) + +interface Props { + a: (x: string) => T; + b: (arg: T) => void; +} + +declare function Foo(props: Props): null; + +Foo({ + ...{ + a: (x) => 10, + b: (arg) => { + arg.toString(); + }, + }, +}); \ No newline at end of file From 0c72dc2feb31601de767ac5bd58ea367e1b10600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 23 Mar 2023 00:24:32 +0100 Subject: [PATCH 3/3] update old baseline --- ...jsxGenericComponentWithSpreadingResultOfGenericFunction.types | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types index 7d6093bcd9efb..be35455d7bdfd 100644 --- a/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types +++ b/tests/baselines/reference/jsxGenericComponentWithSpreadingResultOfGenericFunction.types @@ -21,7 +21,6 @@ declare const otherProps: { bar: string, qwe: boolean } declare function GenericComponent(props: T): null >GenericComponent : (props: T) => null >props : T ->null : null ; // no error > : JSX.Element