Fixed issue with spreading a generic call expression into generic JSX and gather intra expression inference sites from spread expressions (#53444)

This commit is contained in:
Mateusz Burzyński 2023-05-08 22:53:15 +02:00 committed by GitHub
parent 04d4580f4e
commit 6947c98929
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 260 additions and 8 deletions

View File

@ -30106,7 +30106,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);
@ -30208,7 +30208,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
@ -30228,7 +30228,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) {
@ -30428,7 +30428,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;
@ -30465,7 +30465,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!;
@ -30478,7 +30478,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, checkMode & CheckMode.Inferential));
if (isTypeAny(exprType)) {
hasSpreadAnyType = true;
}

View File

@ -212,4 +212,19 @@ tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInf
let test1: "a" = u
}
})
interface Props<T> {
a: (x: string) => T;
b: (arg: T) => void;
}
declare function Foo<T>(props: Props<T>): null;
Foo({
...{
a: (x) => 10,
b: (arg) => {
arg.toString();
},
},
});

View File

@ -197,11 +197,37 @@ branch({
let test1: "a" = u
}
})
interface Props<T> {
a: (x: string) => T;
b: (arg: T) => void;
}
declare function Foo<T>(props: Props<T>): 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: <T, U extends T>(_: {
then: (u: U) => void;
}) => void;
declare const x: "a" | "b";
interface Props<T> {
a: (x: string) => T;
b: (arg: T) => void;
}
declare function Foo<T>(props: Props<T>): null;

View File

@ -626,3 +626,45 @@ branch({
}
})
interface Props<T> {
>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<T>(props: Props<T>): 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, --, --))
},
},
});

View File

@ -659,3 +659,45 @@ branch({
}
})
interface Props<T> {
a: (x: string) => T;
>a : (x: string) => T
>x : string
b: (arg: T) => void;
>b : (arg: T) => void
>arg : T
}
declare function Foo<T>(props: Props<T>): null;
>Foo : <T>(props: Props<T>) => null
>props : Props<T>
Foo({
>Foo({ ...{ a: (x) => 10, b: (arg) => { arg.toString(); }, },}) : null
>Foo : <T>(props: Props<T>) => 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
},
},
});

View File

@ -0,0 +1,47 @@
=== tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx ===
/// <reference path="react16.d.ts" />
// repro #51577
declare function omit<T, K extends string>(names: readonly K[], obj: T): Omit<T, K>;
>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<K extends string>(names: readonly K[]): <T>(obj: T) => Omit<T, K>;
>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<T>(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))
<GenericComponent {...omit(['bar'], otherProps)} />; // 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))

View File

@ -0,0 +1,35 @@
=== tests/cases/compiler/jsxGenericComponentWithSpreadingResultOfGenericFunction.tsx ===
/// <reference path="react16.d.ts" />
// repro #51577
declare function omit<T, K extends string>(names: readonly K[], obj: T): Omit<T, K>;
>omit : { <T, K extends string>(names: readonly K[], obj: T): Omit<T, K>; <K extends string>(names: readonly K[]): <T>(obj: T) => Omit<T, K>; }
>names : readonly K[]
>obj : T
declare function omit<K extends string>(names: readonly K[]): <T>(obj: T) => Omit<T, K>;
>omit : { <T, K extends string>(names: readonly K[], obj: T): Omit<T, K>; <K extends string>(names: readonly K[]): <T>(obj: T) => Omit<T, K>; }
>names : readonly K[]
>obj : T
declare const otherProps: { bar: string, qwe: boolean }
>otherProps : { bar: string; qwe: boolean; }
>bar : string
>qwe : boolean
declare function GenericComponent<T>(props: T): null
>GenericComponent : <T>(props: T) => null
>props : T
<GenericComponent {...omit(['bar'], otherProps)} />; // no error
><GenericComponent {...omit(['bar'], otherProps)} /> : JSX.Element
>GenericComponent : <T>(props: T) => null
>omit(['bar'], otherProps) : Omit<{ bar: string; qwe: boolean; }, "bar">
>omit : { <T, K extends string>(names: readonly K[], obj: T): Omit<T, K>; <K extends string>(names: readonly K[]): <T>(obj: T) => Omit<T, K>; }
>['bar'] : "bar"[]
>'bar' : "bar"
>otherProps : { bar: string; qwe: boolean; }

View File

@ -0,0 +1,18 @@
// @strict: true
// @noEmit: true
// @jsx: preserve
/// <reference path="/.lib/react16.d.ts" />
// repro #51577
declare function omit<T, K extends string>(names: readonly K[], obj: T): Omit<T, K>;
declare function omit<K extends string>(names: readonly K[]): <T>(obj: T) => Omit<T, K>;
declare const otherProps: { bar: string, qwe: boolean }
declare function GenericComponent<T>(props: T): null
<GenericComponent {...omit(['bar'], otherProps)} />; // no error

View File

@ -199,3 +199,19 @@ branch({
let test1: "a" = u
}
})
interface Props<T> {
a: (x: string) => T;
b: (arg: T) => void;
}
declare function Foo<T>(props: Props<T>): null;
Foo({
...{
a: (x) => 10,
b: (arg) => {
arg.toString();
},
},
});