Skip to content

Commit e0f136b

Browse files
* Merge pull request #30856 from Microsoft/nonInferrableType Add a proper non-inferrable type * Merge pull request #30963 from Microsoft/fixObjectFlagsPropagation Fix object flags propagation
1 parent 4c6ac3e commit e0f136b

File tree

6 files changed

+299
-29
lines changed

6 files changed

+299
-29
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,10 @@ namespace ts {
403403
const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
404404
const errorType = createIntrinsicType(TypeFlags.Any, "error");
405405
const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
406-
const undefinedType = createNullableType(TypeFlags.Undefined, "undefined", 0);
407-
const undefinedWideningType = strictNullChecks ? undefinedType : createNullableType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType);
408-
const nullType = createNullableType(TypeFlags.Null, "null", 0);
409-
const nullWideningType = strictNullChecks ? nullType : createNullableType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType);
406+
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
407+
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType);
408+
const nullType = createIntrinsicType(TypeFlags.Null, "null");
409+
const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType);
410410
const stringType = createIntrinsicType(TypeFlags.String, "string");
411411
const numberType = createIntrinsicType(TypeFlags.Number, "number");
412412
const bigintType = createIntrinsicType(TypeFlags.BigInt, "bigint");
@@ -432,6 +432,7 @@ namespace ts {
432432
const voidType = createIntrinsicType(TypeFlags.Void, "void");
433433
const neverType = createIntrinsicType(TypeFlags.Never, "never");
434434
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
435+
const nonInferrableType = createIntrinsicType(TypeFlags.Never, "never", ObjectFlags.NonInferrableType);
435436
const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never");
436437
const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object");
437438
const stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]);
@@ -452,7 +453,7 @@ namespace ts {
452453
const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
453454
// The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated
454455
// in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes.
455-
anyFunctionType.objectFlags |= ObjectFlags.ContainsAnyFunctionType;
456+
anyFunctionType.objectFlags |= ObjectFlags.NonInferrableType;
456457

457458
const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
458459
const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
@@ -2753,14 +2754,9 @@ namespace ts {
27532754
return result;
27542755
}
27552756

2756-
function createIntrinsicType(kind: TypeFlags, intrinsicName: string): IntrinsicType {
2757+
function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags: ObjectFlags = 0): IntrinsicType {
27572758
const type = <IntrinsicType>createType(kind);
27582759
type.intrinsicName = intrinsicName;
2759-
return type;
2760-
}
2761-
2762-
function createNullableType(kind: TypeFlags, intrinsicName: string, objectFlags: ObjectFlags): NullableType {
2763-
const type = createIntrinsicType(kind, intrinsicName);
27642760
type.objectFlags = objectFlags;
27652761
return type;
27662762
}
@@ -14137,7 +14133,7 @@ namespace ts {
1413714133
const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray,
1413814134
stringIndexInfo && createIndexInfo(getWidenedType(stringIndexInfo.type), stringIndexInfo.isReadonly),
1413914135
numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly));
14140-
result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Retain js literal flag through widening
14136+
result.objectFlags |= (getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType)); // Retain js literal flag through widening
1414114137
return result;
1414214138
}
1414314139

@@ -14455,16 +14451,10 @@ namespace ts {
1445514451
}
1445614452

1445714453
function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) {
14458-
const properties = getPropertiesOfType(source);
14459-
if (properties.length === 0 && !getIndexInfoOfType(source, IndexKind.String)) {
14460-
return undefined;
14461-
}
1446214454
// If any property contains context sensitive functions that have been skipped, the source type
1446314455
// is incomplete and we can't infer a meaningful input type.
14464-
for (const prop of properties) {
14465-
if (getObjectFlags(getTypeOfSymbol(prop)) & ObjectFlags.ContainsAnyFunctionType) {
14466-
return undefined;
14467-
}
14456+
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || getPropertiesOfType(source).length === 0 && !getIndexInfoOfType(source, IndexKind.String)) {
14457+
return undefined;
1446814458
}
1446914459
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
1447014460
// applied to the element type(s).
@@ -14619,7 +14609,7 @@ namespace ts {
1461914609
// not contain anyFunctionType when we come back to this argument for its second round
1462014610
// of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard
1462114611
// when constructing types from type parameters that had no inference candidates).
14622-
if (getObjectFlags(source) & ObjectFlags.ContainsAnyFunctionType || source === silentNeverType || (priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType))) {
14612+
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === silentNeverType || (priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType))) {
1462314613
return;
1462414614
}
1462514615
const inference = getInferenceInfoForType(target);
@@ -14932,7 +14922,7 @@ namespace ts {
1493214922
const sourceLen = sourceSignatures.length;
1493314923
const targetLen = targetSignatures.length;
1493414924
const len = sourceLen < targetLen ? sourceLen : targetLen;
14935-
const skipParameters = !!(getObjectFlags(source) & ObjectFlags.ContainsAnyFunctionType);
14925+
const skipParameters = !!(getObjectFlags(source) & ObjectFlags.NonInferrableType);
1493614926
for (let i = 0; i < len; i++) {
1493714927
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getBaseSignature(targetSignatures[targetLen - len + i]), skipParameters);
1493814928
}
@@ -21052,7 +21042,7 @@ namespace ts {
2105221042
// returns a function type, we choose to defer processing. This narrowly permits function composition
2105321043
// operators to flow inferences through return types, but otherwise processes calls right away. We
2105421044
// use the resolvingSignature singleton to indicate that we deferred processing. This result will be
21055-
// propagated out and eventually turned into silentNeverType (a type that is assignable to anything and
21045+
// propagated out and eventually turned into nonInferrableType (a type that is assignable to anything and
2105621046
// from which we never make inferences).
2105721047
if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) {
2105821048
skippedGenericFunction(node, checkMode);
@@ -21535,8 +21525,8 @@ namespace ts {
2153521525
const signature = getResolvedSignature(node, /*candidatesOutArray*/ undefined, checkMode);
2153621526
if (signature === resolvingSignature) {
2153721527
// CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that
21538-
// returns a function type. We defer checking and return anyFunctionType.
21539-
return silentNeverType;
21528+
// returns a function type. We defer checking and return nonInferrableType.
21529+
return nonInferrableType;
2154021530
}
2154121531

2154221532
if (node.expression.kind === SyntaxKind.SuperKeyword) {
@@ -22343,7 +22333,7 @@ namespace ts {
2234322333
const returnType = getReturnTypeFromBody(node, checkMode);
2234422334
const returnOnlySignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
2234522335
const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, undefined, undefined);
22346-
returnOnlyType.objectFlags |= ObjectFlags.ContainsAnyFunctionType;
22336+
returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType;
2234722337
return links.contextFreeType = returnOnlyType;
2234822338
}
2234922339
return anyFunctionType;

src/compiler/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3944,7 +3944,7 @@ namespace ts {
39443944
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
39453945
StructuredOrInstantiable = StructuredType | Instantiable,
39463946
/* @internal */
3947-
ObjectFlagsType = Nullable | Object | Union | Intersection,
3947+
ObjectFlagsType = Nullable | Never | Object | Union | Intersection,
39483948
// 'Narrowable' types are types where narrowing actually narrows.
39493949
// This *should* be every type other than null, undefined, void, and never
39503950
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
@@ -4064,12 +4064,12 @@ namespace ts {
40644064
/* @internal */
40654065
ContainsObjectLiteral = 1 << 18, // Type is or contains object literal type
40664066
/* @internal */
4067-
ContainsAnyFunctionType = 1 << 19, // Type is or contains the anyFunctionType
4067+
NonInferrableType = 1 << 19, // Type is or contains anyFunctionType or silentNeverType
40684068
ClassOrInterface = Class | Interface,
40694069
/* @internal */
40704070
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
40714071
/* @internal */
4072-
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType
4072+
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | NonInferrableType
40734073
}
40744074

40754075
/* @internal */
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [genericFunctionInference2.ts]
2+
// Repro from #30685
3+
4+
type Reducer<S> = (state: S) => S;
5+
declare function combineReducers<S>(reducers: { [K in keyof S]: Reducer<S[K]> }): Reducer<S>;
6+
7+
type MyState = { combined: { foo: number } };
8+
declare const foo: Reducer<MyState['combined']['foo']>;
9+
10+
const myReducer1: Reducer<MyState> = combineReducers({
11+
combined: combineReducers({ foo }),
12+
});
13+
14+
const myReducer2 = combineReducers({
15+
combined: combineReducers({ foo }),
16+
});
17+
18+
// Repro from #30942
19+
20+
declare function withH<T, U>(handlerCreators: HandleCreatorsFactory<T, U>): U;
21+
22+
type Props = { out: number }
23+
24+
type HandleCreatorsFactory<T, U> = (initialProps: T) => { [P in keyof U]: (props: T) => U[P] };
25+
26+
const enhancer4 = withH((props: Props) => ({
27+
onChange: (props) => (e: any) => {},
28+
onSubmit: (props) => (e: any) => {},
29+
}));
30+
31+
enhancer4.onChange(null);
32+
33+
34+
//// [genericFunctionInference2.js]
35+
// Repro from #30685
36+
var myReducer1 = combineReducers({
37+
combined: combineReducers({ foo: foo })
38+
});
39+
var myReducer2 = combineReducers({
40+
combined: combineReducers({ foo: foo })
41+
});
42+
var enhancer4 = withH(function (props) { return ({
43+
onChange: function (props) { return function (e) { }; },
44+
onSubmit: function (props) { return function (e) { }; }
45+
}); });
46+
enhancer4.onChange(null);
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
=== tests/cases/compiler/genericFunctionInference2.ts ===
2+
// Repro from #30685
3+
4+
type Reducer<S> = (state: S) => S;
5+
>Reducer : Symbol(Reducer, Decl(genericFunctionInference2.ts, 0, 0))
6+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 2, 13))
7+
>state : Symbol(state, Decl(genericFunctionInference2.ts, 2, 19))
8+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 2, 13))
9+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 2, 13))
10+
11+
declare function combineReducers<S>(reducers: { [K in keyof S]: Reducer<S[K]> }): Reducer<S>;
12+
>combineReducers : Symbol(combineReducers, Decl(genericFunctionInference2.ts, 2, 34))
13+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 3, 33))
14+
>reducers : Symbol(reducers, Decl(genericFunctionInference2.ts, 3, 36))
15+
>K : Symbol(K, Decl(genericFunctionInference2.ts, 3, 49))
16+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 3, 33))
17+
>Reducer : Symbol(Reducer, Decl(genericFunctionInference2.ts, 0, 0))
18+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 3, 33))
19+
>K : Symbol(K, Decl(genericFunctionInference2.ts, 3, 49))
20+
>Reducer : Symbol(Reducer, Decl(genericFunctionInference2.ts, 0, 0))
21+
>S : Symbol(S, Decl(genericFunctionInference2.ts, 3, 33))
22+
23+
type MyState = { combined: { foo: number } };
24+
>MyState : Symbol(MyState, Decl(genericFunctionInference2.ts, 3, 93))
25+
>combined : Symbol(combined, Decl(genericFunctionInference2.ts, 5, 16))
26+
>foo : Symbol(foo, Decl(genericFunctionInference2.ts, 5, 28))
27+
28+
declare const foo: Reducer<MyState['combined']['foo']>;
29+
>foo : Symbol(foo, Decl(genericFunctionInference2.ts, 6, 13))
30+
>Reducer : Symbol(Reducer, Decl(genericFunctionInference2.ts, 0, 0))
31+
>MyState : Symbol(MyState, Decl(genericFunctionInference2.ts, 3, 93))
32+
33+
const myReducer1: Reducer<MyState> = combineReducers({
34+
>myReducer1 : Symbol(myReducer1, Decl(genericFunctionInference2.ts, 8, 5))
35+
>Reducer : Symbol(Reducer, Decl(genericFunctionInference2.ts, 0, 0))
36+
>MyState : Symbol(MyState, Decl(genericFunctionInference2.ts, 3, 93))
37+
>combineReducers : Symbol(combineReducers, Decl(genericFunctionInference2.ts, 2, 34))
38+
39+
combined: combineReducers({ foo }),
40+
>combined : Symbol(combined, Decl(genericFunctionInference2.ts, 8, 54))
41+
>combineReducers : Symbol(combineReducers, Decl(genericFunctionInference2.ts, 2, 34))
42+
>foo : Symbol(foo, Decl(genericFunctionInference2.ts, 9, 31))
43+
44+
});
45+
46+
const myReducer2 = combineReducers({
47+
>myReducer2 : Symbol(myReducer2, Decl(genericFunctionInference2.ts, 12, 5))
48+
>combineReducers : Symbol(combineReducers, Decl(genericFunctionInference2.ts, 2, 34))
49+
50+
combined: combineReducers({ foo }),
51+
>combined : Symbol(combined, Decl(genericFunctionInference2.ts, 12, 36))
52+
>combineReducers : Symbol(combineReducers, Decl(genericFunctionInference2.ts, 2, 34))
53+
>foo : Symbol(foo, Decl(genericFunctionInference2.ts, 13, 31))
54+
55+
});
56+
57+
// Repro from #30942
58+
59+
declare function withH<T, U>(handlerCreators: HandleCreatorsFactory<T, U>): U;
60+
>withH : Symbol(withH, Decl(genericFunctionInference2.ts, 14, 3))
61+
>T : Symbol(T, Decl(genericFunctionInference2.ts, 18, 23))
62+
>U : Symbol(U, Decl(genericFunctionInference2.ts, 18, 25))
63+
>handlerCreators : Symbol(handlerCreators, Decl(genericFunctionInference2.ts, 18, 29))
64+
>HandleCreatorsFactory : Symbol(HandleCreatorsFactory, Decl(genericFunctionInference2.ts, 20, 28))
65+
>T : Symbol(T, Decl(genericFunctionInference2.ts, 18, 23))
66+
>U : Symbol(U, Decl(genericFunctionInference2.ts, 18, 25))
67+
>U : Symbol(U, Decl(genericFunctionInference2.ts, 18, 25))
68+
69+
type Props = { out: number }
70+
>Props : Symbol(Props, Decl(genericFunctionInference2.ts, 18, 78))
71+
>out : Symbol(out, Decl(genericFunctionInference2.ts, 20, 14))
72+
73+
type HandleCreatorsFactory<T, U> = (initialProps: T) => { [P in keyof U]: (props: T) => U[P] };
74+
>HandleCreatorsFactory : Symbol(HandleCreatorsFactory, Decl(genericFunctionInference2.ts, 20, 28))
75+
>T : Symbol(T, Decl(genericFunctionInference2.ts, 22, 27))
76+
>U : Symbol(U, Decl(genericFunctionInference2.ts, 22, 29))
77+
>initialProps : Symbol(initialProps, Decl(genericFunctionInference2.ts, 22, 36))
78+
>T : Symbol(T, Decl(genericFunctionInference2.ts, 22, 27))
79+
>P : Symbol(P, Decl(genericFunctionInference2.ts, 22, 59))
80+
>U : Symbol(U, Decl(genericFunctionInference2.ts, 22, 29))
81+
>props : Symbol(props, Decl(genericFunctionInference2.ts, 22, 75))
82+
>T : Symbol(T, Decl(genericFunctionInference2.ts, 22, 27))
83+
>U : Symbol(U, Decl(genericFunctionInference2.ts, 22, 29))
84+
>P : Symbol(P, Decl(genericFunctionInference2.ts, 22, 59))
85+
86+
const enhancer4 = withH((props: Props) => ({
87+
>enhancer4 : Symbol(enhancer4, Decl(genericFunctionInference2.ts, 24, 5))
88+
>withH : Symbol(withH, Decl(genericFunctionInference2.ts, 14, 3))
89+
>props : Symbol(props, Decl(genericFunctionInference2.ts, 24, 25))
90+
>Props : Symbol(Props, Decl(genericFunctionInference2.ts, 18, 78))
91+
92+
onChange: (props) => (e: any) => {},
93+
>onChange : Symbol(onChange, Decl(genericFunctionInference2.ts, 24, 44))
94+
>props : Symbol(props, Decl(genericFunctionInference2.ts, 25, 15))
95+
>e : Symbol(e, Decl(genericFunctionInference2.ts, 25, 26))
96+
97+
onSubmit: (props) => (e: any) => {},
98+
>onSubmit : Symbol(onSubmit, Decl(genericFunctionInference2.ts, 25, 40))
99+
>props : Symbol(props, Decl(genericFunctionInference2.ts, 26, 15))
100+
>e : Symbol(e, Decl(genericFunctionInference2.ts, 26, 26))
101+
102+
}));
103+
104+
enhancer4.onChange(null);
105+
>enhancer4.onChange : Symbol(onChange, Decl(genericFunctionInference2.ts, 24, 44))
106+
>enhancer4 : Symbol(enhancer4, Decl(genericFunctionInference2.ts, 24, 5))
107+
>onChange : Symbol(onChange, Decl(genericFunctionInference2.ts, 24, 44))
108+

0 commit comments

Comments
 (0)