diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ebe2d1c84b566..85a8aefd2dec9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -785,11 +785,10 @@ namespace ts { const errorTypes = new Map(); const anyType = createIntrinsicType(TypeFlags.Any, "any"); - const autoType = createIntrinsicType(TypeFlags.Any, "any"); + const autoType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.NonInferrableType); const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); const errorType = createIntrinsicType(TypeFlags.Any, "error"); const unresolvedType = createIntrinsicType(TypeFlags.Any, "unresolved"); - const nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType); const intrinsicMarkerType = createIntrinsicType(TypeFlags.Any, "intrinsic"); const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); @@ -818,8 +817,7 @@ namespace ts { const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol"); const voidType = createIntrinsicType(TypeFlags.Void, "void"); const neverType = createIntrinsicType(TypeFlags.Never, "never"); - const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); - const nonInferrableType = createIntrinsicType(TypeFlags.Never, "never", ObjectFlags.NonInferrableType); + const silentNeverType = createIntrinsicType(TypeFlags.Never, "never", ObjectFlags.NonInferrableType); const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never"); const unreachableNeverType = createIntrinsicType(TypeFlags.Never, "never"); const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); @@ -9456,11 +9454,7 @@ namespace ts { if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) { reportImplicitAny(element, anyType); } - // When we're including the pattern in the type (an indication we're obtaining a contextual type), we - // use the non-inferrable any type. Inference will never directly infer this type, but it is possible - // to infer a type that contains it, e.g. for a binding pattern like [foo] or { foo }. In such cases, - // widening of the binding pattern type substitutes a regular any for the non-inferrable any. - return includePatternInType ? nonInferrableAnyType : anyType; + return anyType; } // Return the type implied by an object binding pattern @@ -13499,12 +13493,12 @@ namespace ts { // This function is used to propagate certain flags when creating new object type references and union types. // It is only necessary to do so if a constituent type might be the undefined type, the null type, the type - // of an object literal or the anyFunctionType. This is because there are operations in the type checker + // of an object literal or a non-inferrable type. This is because there are operations in the type checker // that care about the presence of such types at arbitrary depth in a containing type. - function getPropagatingFlagsOfTypes(types: readonly Type[], excludeKinds: TypeFlags): ObjectFlags { + function getPropagatingFlagsOfTypes(types: readonly Type[], excludeKinds?: TypeFlags): ObjectFlags { let result: ObjectFlags = 0; for (const type of types) { - if (!(type.flags & excludeKinds)) { + if (excludeKinds === undefined || !(type.flags & excludeKinds)) { result |= getObjectFlags(type); } } @@ -13517,7 +13511,7 @@ namespace ts { if (!type) { type = createObjectType(ObjectFlags.Reference, target.symbol) as TypeReference; target.instantiations.set(id, type); - type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0; + type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments) : 0; type.target = target; type.resolvedTypeArguments = typeArguments; } @@ -17196,6 +17190,7 @@ namespace ts { result.mapper = mapper; result.aliasSymbol = aliasSymbol || type.aliasSymbol; result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + result.objectFlags |= result.aliasTypeArguments ? getPropagatingFlagsOfTypes(result.aliasTypeArguments) : 0; return result; } @@ -22422,10 +22417,13 @@ namespace ts { propagationType = savePropagationType; return; } - if (source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) { - // Source and target are types originating in the same generic type alias declaration. - // Simply infer from source type arguments to target type arguments. - inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); + if (source.aliasSymbol && source.aliasSymbol === target.aliasSymbol) { + if (source.aliasTypeArguments) { + // Source and target are types originating in the same generic type alias declaration. + // Simply infer from source type arguments to target type arguments. + inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); + } + // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; } if (source === target && source.flags & TypeFlags.UnionOrIntersection) { @@ -22481,18 +22479,26 @@ namespace ts { target = getActualTypeVariable(target); } if (target.flags & TypeFlags.TypeVariable) { - // If target is a type parameter, make an inference, unless the source type contains - // the anyFunctionType (the wildcard type that's used to avoid contextually typing functions). - // Because the anyFunctionType is internal, it should not be exposed to the user by adding - // it as an inference candidate. Hopefully, a better candidate will come along that does - // not contain anyFunctionType when we come back to this argument for its second round - // of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard - // when constructing types from type parameters that had no inference candidates). - if (source === nonInferrableAnyType || source === silentNeverType || (priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType)) || isFromInferenceBlockedSource(source)) { + // Skip inference if the source is "blocked", which is used by the language service to + // prevent inference on nodes currently being edited. + if (isFromInferenceBlockedSource(source)) { return; } const inference = getInferenceInfoForType(target); if (inference) { + // If target is a type parameter, make an inference, unless the source type contains + // a "non-inferrable" type. Types with this flag set are markers used to prevent inference. + // + // For example: + // - anyFunctionType is a wildcard type that's used to avoid contextually typing functions; + // it's internal, so should not be exposed to the user by adding it as a candidate. + // - autoType (and autoArrayType) is a special "any" used in control flow; like anyFunctionType, + // it's internal and should not be observable. + // - silentNeverType is returned by getInferredType when instantiating a generic function for + // inference (and a type variable has no mapping). + // + // This flag is infectious; if we produce Box (where never is silentNeverType), Box is + // also non-inferrable. if (getObjectFlags(source) & ObjectFlags.NonInferrableType) { return; } @@ -23043,21 +23049,18 @@ namespace ts { const sourceLen = sourceSignatures.length; const targetLen = targetSignatures.length; const len = sourceLen < targetLen ? sourceLen : targetLen; - const skipParameters = !!(getObjectFlags(source) & ObjectFlags.NonInferrableType); for (let i = 0; i < len; i++) { - inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i]), skipParameters); + inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); } } - function inferFromSignature(source: Signature, target: Signature, skipParameters: boolean) { - if (!skipParameters) { - const saveBivariant = bivariant; - const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; - // Once we descend into a bivariant signature we remain bivariant for all nested inferences - bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; - applyToParameterTypes(source, target, inferFromContravariantTypes); - bivariant = saveBivariant; - } + function inferFromSignature(source: Signature, target: Signature) { + const saveBivariant = bivariant; + const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; + // Once we descend into a bivariant signature we remain bivariant for all nested inferences + bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; + applyToParameterTypes(source, target, inferFromContravariantTypes); + bivariant = saveBivariant; applyToReturnTypes(source, target, inferFromTypes); } @@ -31263,7 +31266,7 @@ namespace ts { // returns a function type, we choose to defer processing. This narrowly permits function composition // operators to flow inferences through return types, but otherwise processes calls right away. We // use the resolvingSignature singleton to indicate that we deferred processing. This result will be - // propagated out and eventually turned into nonInferrableType (a type that is assignable to anything and + // propagated out and eventually turned into silentNeverType (a type that is assignable to anything and // from which we never make inferences). if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) { skippedGenericFunction(node, checkMode); @@ -31898,8 +31901,8 @@ namespace ts { const signature = getResolvedSignature(node, /*candidatesOutArray*/ undefined, checkMode); if (signature === resolvingSignature) { // CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that - // returns a function type. We defer checking and return nonInferrableType. - return nonInferrableType; + // returns a function type. We defer checking and return silentNeverType. + return silentNeverType; } checkDeprecatedSignature(signature, node); diff --git a/tests/baselines/reference/nonInferrableTypePropagation1.js b/tests/baselines/reference/nonInferrableTypePropagation1.js new file mode 100644 index 0000000000000..ae1fbe7976582 --- /dev/null +++ b/tests/baselines/reference/nonInferrableTypePropagation1.js @@ -0,0 +1,34 @@ +//// [nonInferrableTypePropagation1.ts] +type Op = (thing: Thing) => Thing; +type Thing = { + value: T; + pipe( + opA: Op, + opB: Op, + ): Thing; +}; +type Box = { data: V }; + +declare const thing: Thing; + +declare function map(project: (value: T) => R): Op; +declare function tap(next: (value: T) => void): Op; +declare function box(data: V): Box; +declare function createAndUnbox(factory: () => Thing>): Thing; +declare function log(value: any): void; + +const result1 = createAndUnbox(() => thing.pipe( + map((data) => box(data)), + tap((v) => log(v)), +)); + +const result2 = createAndUnbox(() => thing.pipe( + tap((v) => log(v)), + map((data) => box(data)), +)); + + +//// [nonInferrableTypePropagation1.js] +"use strict"; +var result1 = createAndUnbox(function () { return thing.pipe(map(function (data) { return box(data); }), tap(function (v) { return log(v); })); }); +var result2 = createAndUnbox(function () { return thing.pipe(tap(function (v) { return log(v); }), map(function (data) { return box(data); })); }); diff --git a/tests/baselines/reference/nonInferrableTypePropagation1.symbols b/tests/baselines/reference/nonInferrableTypePropagation1.symbols new file mode 100644 index 0000000000000..00b78ed84841d --- /dev/null +++ b/tests/baselines/reference/nonInferrableTypePropagation1.symbols @@ -0,0 +1,138 @@ +=== tests/cases/compiler/nonInferrableTypePropagation1.ts === +type Op = (thing: Thing) => Thing; +>Op : Symbol(Op, Decl(nonInferrableTypePropagation1.ts, 0, 0)) +>I : Symbol(I, Decl(nonInferrableTypePropagation1.ts, 0, 8)) +>O : Symbol(O, Decl(nonInferrableTypePropagation1.ts, 0, 10)) +>thing : Symbol(thing, Decl(nonInferrableTypePropagation1.ts, 0, 17)) +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) +>I : Symbol(I, Decl(nonInferrableTypePropagation1.ts, 0, 8)) +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) +>O : Symbol(O, Decl(nonInferrableTypePropagation1.ts, 0, 10)) + +type Thing = { +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 1, 11)) + + value: T; +>value : Symbol(value, Decl(nonInferrableTypePropagation1.ts, 1, 17)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 1, 11)) + + pipe( +>pipe : Symbol(pipe, Decl(nonInferrableTypePropagation1.ts, 2, 13)) +>A : Symbol(A, Decl(nonInferrableTypePropagation1.ts, 3, 9)) +>B : Symbol(B, Decl(nonInferrableTypePropagation1.ts, 3, 11)) + + opA: Op, +>opA : Symbol(opA, Decl(nonInferrableTypePropagation1.ts, 3, 15)) +>Op : Symbol(Op, Decl(nonInferrableTypePropagation1.ts, 0, 0)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 1, 11)) +>A : Symbol(A, Decl(nonInferrableTypePropagation1.ts, 3, 9)) + + opB: Op, +>opB : Symbol(opB, Decl(nonInferrableTypePropagation1.ts, 4, 22)) +>Op : Symbol(Op, Decl(nonInferrableTypePropagation1.ts, 0, 0)) +>A : Symbol(A, Decl(nonInferrableTypePropagation1.ts, 3, 9)) +>B : Symbol(B, Decl(nonInferrableTypePropagation1.ts, 3, 11)) + + ): Thing; +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) +>B : Symbol(B, Decl(nonInferrableTypePropagation1.ts, 3, 11)) + +}; +type Box = { data: V }; +>Box : Symbol(Box, Decl(nonInferrableTypePropagation1.ts, 7, 2)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 8, 9)) +>data : Symbol(data, Decl(nonInferrableTypePropagation1.ts, 8, 15)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 8, 9)) + +declare const thing: Thing; +>thing : Symbol(thing, Decl(nonInferrableTypePropagation1.ts, 10, 13)) +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) + +declare function map(project: (value: T) => R): Op; +>map : Symbol(map, Decl(nonInferrableTypePropagation1.ts, 10, 35)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 12, 21)) +>R : Symbol(R, Decl(nonInferrableTypePropagation1.ts, 12, 23)) +>project : Symbol(project, Decl(nonInferrableTypePropagation1.ts, 12, 27)) +>value : Symbol(value, Decl(nonInferrableTypePropagation1.ts, 12, 37)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 12, 21)) +>R : Symbol(R, Decl(nonInferrableTypePropagation1.ts, 12, 23)) +>Op : Symbol(Op, Decl(nonInferrableTypePropagation1.ts, 0, 0)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 12, 21)) +>R : Symbol(R, Decl(nonInferrableTypePropagation1.ts, 12, 23)) + +declare function tap(next: (value: T) => void): Op; +>tap : Symbol(tap, Decl(nonInferrableTypePropagation1.ts, 12, 63)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 13, 21)) +>next : Symbol(next, Decl(nonInferrableTypePropagation1.ts, 13, 24)) +>value : Symbol(value, Decl(nonInferrableTypePropagation1.ts, 13, 31)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 13, 21)) +>Op : Symbol(Op, Decl(nonInferrableTypePropagation1.ts, 0, 0)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 13, 21)) +>T : Symbol(T, Decl(nonInferrableTypePropagation1.ts, 13, 21)) + +declare function box(data: V): Box; +>box : Symbol(box, Decl(nonInferrableTypePropagation1.ts, 13, 60)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 14, 21)) +>data : Symbol(data, Decl(nonInferrableTypePropagation1.ts, 14, 24)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 14, 21)) +>Box : Symbol(Box, Decl(nonInferrableTypePropagation1.ts, 7, 2)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 14, 21)) + +declare function createAndUnbox(factory: () => Thing>): Thing; +>createAndUnbox : Symbol(createAndUnbox, Decl(nonInferrableTypePropagation1.ts, 14, 41)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 15, 32)) +>factory : Symbol(factory, Decl(nonInferrableTypePropagation1.ts, 15, 35)) +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 15, 32)) +>Box : Symbol(Box, Decl(nonInferrableTypePropagation1.ts, 7, 2)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 15, 32)) +>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46)) +>V : Symbol(V, Decl(nonInferrableTypePropagation1.ts, 15, 32)) + +declare function log(value: any): void; +>log : Symbol(log, Decl(nonInferrableTypePropagation1.ts, 15, 79)) +>value : Symbol(value, Decl(nonInferrableTypePropagation1.ts, 16, 21)) + +const result1 = createAndUnbox(() => thing.pipe( +>result1 : Symbol(result1, Decl(nonInferrableTypePropagation1.ts, 18, 5)) +>createAndUnbox : Symbol(createAndUnbox, Decl(nonInferrableTypePropagation1.ts, 14, 41)) +>thing.pipe : Symbol(pipe, Decl(nonInferrableTypePropagation1.ts, 2, 13)) +>thing : Symbol(thing, Decl(nonInferrableTypePropagation1.ts, 10, 13)) +>pipe : Symbol(pipe, Decl(nonInferrableTypePropagation1.ts, 2, 13)) + + map((data) => box(data)), +>map : Symbol(map, Decl(nonInferrableTypePropagation1.ts, 10, 35)) +>data : Symbol(data, Decl(nonInferrableTypePropagation1.ts, 19, 9)) +>box : Symbol(box, Decl(nonInferrableTypePropagation1.ts, 13, 60)) +>data : Symbol(data, Decl(nonInferrableTypePropagation1.ts, 19, 9)) + + tap((v) => log(v)), +>tap : Symbol(tap, Decl(nonInferrableTypePropagation1.ts, 12, 63)) +>v : Symbol(v, Decl(nonInferrableTypePropagation1.ts, 20, 9)) +>log : Symbol(log, Decl(nonInferrableTypePropagation1.ts, 15, 79)) +>v : Symbol(v, Decl(nonInferrableTypePropagation1.ts, 20, 9)) + +)); + +const result2 = createAndUnbox(() => thing.pipe( +>result2 : Symbol(result2, Decl(nonInferrableTypePropagation1.ts, 23, 5)) +>createAndUnbox : Symbol(createAndUnbox, Decl(nonInferrableTypePropagation1.ts, 14, 41)) +>thing.pipe : Symbol(pipe, Decl(nonInferrableTypePropagation1.ts, 2, 13)) +>thing : Symbol(thing, Decl(nonInferrableTypePropagation1.ts, 10, 13)) +>pipe : Symbol(pipe, Decl(nonInferrableTypePropagation1.ts, 2, 13)) + + tap((v) => log(v)), +>tap : Symbol(tap, Decl(nonInferrableTypePropagation1.ts, 12, 63)) +>v : Symbol(v, Decl(nonInferrableTypePropagation1.ts, 24, 9)) +>log : Symbol(log, Decl(nonInferrableTypePropagation1.ts, 15, 79)) +>v : Symbol(v, Decl(nonInferrableTypePropagation1.ts, 24, 9)) + + map((data) => box(data)), +>map : Symbol(map, Decl(nonInferrableTypePropagation1.ts, 10, 35)) +>data : Symbol(data, Decl(nonInferrableTypePropagation1.ts, 25, 9)) +>box : Symbol(box, Decl(nonInferrableTypePropagation1.ts, 13, 60)) +>data : Symbol(data, Decl(nonInferrableTypePropagation1.ts, 25, 9)) + +)); + diff --git a/tests/baselines/reference/nonInferrableTypePropagation1.types b/tests/baselines/reference/nonInferrableTypePropagation1.types new file mode 100644 index 0000000000000..fd132594192d2 --- /dev/null +++ b/tests/baselines/reference/nonInferrableTypePropagation1.types @@ -0,0 +1,111 @@ +=== tests/cases/compiler/nonInferrableTypePropagation1.ts === +type Op = (thing: Thing) => Thing; +>Op : Op +>thing : Thing + +type Thing = { +>Thing : Thing + + value: T; +>value : T + + pipe( +>pipe : (opA: Op, opB: Op) => Thing + + opA: Op, +>opA : Op + + opB: Op, +>opB : Op + + ): Thing; +}; +type Box = { data: V }; +>Box : Box +>data : V + +declare const thing: Thing; +>thing : Thing + +declare function map(project: (value: T) => R): Op; +>map : (project: (value: T) => R) => Op +>project : (value: T) => R +>value : T + +declare function tap(next: (value: T) => void): Op; +>tap : (next: (value: T) => void) => Op +>next : (value: T) => void +>value : T + +declare function box(data: V): Box; +>box : (data: V) => Box +>data : V + +declare function createAndUnbox(factory: () => Thing>): Thing; +>createAndUnbox : (factory: () => Thing>) => Thing +>factory : () => Thing> + +declare function log(value: any): void; +>log : (value: any) => void +>value : any + +const result1 = createAndUnbox(() => thing.pipe( +>result1 : Thing +>createAndUnbox(() => thing.pipe( map((data) => box(data)), tap((v) => log(v)),)) : Thing +>createAndUnbox : (factory: () => Thing>) => Thing +>() => thing.pipe( map((data) => box(data)), tap((v) => log(v)),) : () => Thing> +>thing.pipe( map((data) => box(data)), tap((v) => log(v)),) : Thing> +>thing.pipe : (opA: Op, opB: Op) => Thing +>thing : Thing +>pipe : (opA: Op, opB: Op) => Thing + + map((data) => box(data)), +>map((data) => box(data)) : Op> +>map : (project: (value: T) => R) => Op +>(data) => box(data) : (data: number) => Box +>data : number +>box(data) : Box +>box : (data: V) => Box +>data : number + + tap((v) => log(v)), +>tap((v) => log(v)) : Op, Box> +>tap : (next: (value: T) => void) => Op +>(v) => log(v) : (v: Box) => void +>v : Box +>log(v) : void +>log : (value: any) => void +>v : Box + +)); + +const result2 = createAndUnbox(() => thing.pipe( +>result2 : Thing +>createAndUnbox(() => thing.pipe( tap((v) => log(v)), map((data) => box(data)),)) : Thing +>createAndUnbox : (factory: () => Thing>) => Thing +>() => thing.pipe( tap((v) => log(v)), map((data) => box(data)),) : () => Thing> +>thing.pipe( tap((v) => log(v)), map((data) => box(data)),) : Thing> +>thing.pipe : (opA: Op, opB: Op) => Thing +>thing : Thing +>pipe : (opA: Op, opB: Op) => Thing + + tap((v) => log(v)), +>tap((v) => log(v)) : Op +>tap : (next: (value: T) => void) => Op +>(v) => log(v) : (v: number) => void +>v : number +>log(v) : void +>log : (value: any) => void +>v : number + + map((data) => box(data)), +>map((data) => box(data)) : Op> +>map : (project: (value: T) => R) => Op +>(data) => box(data) : (data: number) => Box +>data : number +>box(data) : Box +>box : (data: V) => Box +>data : number + +)); + diff --git a/tests/baselines/reference/nonInferrableTypePropagation2.js b/tests/baselines/reference/nonInferrableTypePropagation2.js new file mode 100644 index 0000000000000..1cbd3d1533c9f --- /dev/null +++ b/tests/baselines/reference/nonInferrableTypePropagation2.js @@ -0,0 +1,38 @@ +//// [nonInferrableTypePropagation2.ts] +export interface Predicate { + (a: A): boolean +} + +interface Left { + readonly _tag: 'Left' + readonly left: E +} + +interface Right { + readonly _tag: 'Right' + readonly right: A +} + +type Either = Left | Right; + +interface Refinement { + (a: A): a is B +} + +declare const filter: { + (refinement: Refinement): (as: ReadonlyArray) => ReadonlyArray + (predicate: Predicate): (bs: ReadonlyArray) => ReadonlyArray + (predicate: Predicate): (as: ReadonlyArray) => ReadonlyArray +}; + +declare function pipe(a: A, ab: (a: A) => B): B; +declare function exists(predicate: Predicate): (ma: Either) => boolean; + +declare const es: Either[]; +const x = pipe(es, filter(exists((n) => n > 0))) + + +//// [nonInferrableTypePropagation2.js] +"use strict"; +exports.__esModule = true; +var x = pipe(es, filter(exists(function (n) { return n > 0; }))); diff --git a/tests/baselines/reference/nonInferrableTypePropagation2.symbols b/tests/baselines/reference/nonInferrableTypePropagation2.symbols new file mode 100644 index 0000000000000..681520aa27127 --- /dev/null +++ b/tests/baselines/reference/nonInferrableTypePropagation2.symbols @@ -0,0 +1,136 @@ +=== tests/cases/compiler/nonInferrableTypePropagation2.ts === +export interface Predicate { +>Predicate : Symbol(Predicate, Decl(nonInferrableTypePropagation2.ts, 0, 0)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 0, 27)) + + (a: A): boolean +>a : Symbol(a, Decl(nonInferrableTypePropagation2.ts, 1, 5)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 0, 27)) +} + +interface Left { +>Left : Symbol(Left, Decl(nonInferrableTypePropagation2.ts, 2, 1)) +>E : Symbol(E, Decl(nonInferrableTypePropagation2.ts, 4, 15)) + + readonly _tag: 'Left' +>_tag : Symbol(Left._tag, Decl(nonInferrableTypePropagation2.ts, 4, 19)) + + readonly left: E +>left : Symbol(Left.left, Decl(nonInferrableTypePropagation2.ts, 5, 25)) +>E : Symbol(E, Decl(nonInferrableTypePropagation2.ts, 4, 15)) +} + +interface Right { +>Right : Symbol(Right, Decl(nonInferrableTypePropagation2.ts, 7, 1)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 9, 16)) + + readonly _tag: 'Right' +>_tag : Symbol(Right._tag, Decl(nonInferrableTypePropagation2.ts, 9, 20)) + + readonly right: A +>right : Symbol(Right.right, Decl(nonInferrableTypePropagation2.ts, 10, 26)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 9, 16)) +} + +type Either = Left | Right; +>Either : Symbol(Either, Decl(nonInferrableTypePropagation2.ts, 12, 1)) +>E : Symbol(E, Decl(nonInferrableTypePropagation2.ts, 14, 12)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 14, 14)) +>Left : Symbol(Left, Decl(nonInferrableTypePropagation2.ts, 2, 1)) +>E : Symbol(E, Decl(nonInferrableTypePropagation2.ts, 14, 12)) +>Right : Symbol(Right, Decl(nonInferrableTypePropagation2.ts, 7, 1)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 14, 14)) + +interface Refinement { +>Refinement : Symbol(Refinement, Decl(nonInferrableTypePropagation2.ts, 14, 39)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 16, 21)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 16, 23)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 16, 21)) + + (a: A): a is B +>a : Symbol(a, Decl(nonInferrableTypePropagation2.ts, 17, 5)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 16, 21)) +>a : Symbol(a, Decl(nonInferrableTypePropagation2.ts, 17, 5)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 16, 23)) +} + +declare const filter: { +>filter : Symbol(filter, Decl(nonInferrableTypePropagation2.ts, 20, 13)) + + (refinement: Refinement): (as: ReadonlyArray) => ReadonlyArray +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 21, 5)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 21, 7)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 21, 5)) +>refinement : Symbol(refinement, Decl(nonInferrableTypePropagation2.ts, 21, 21)) +>Refinement : Symbol(Refinement, Decl(nonInferrableTypePropagation2.ts, 14, 39)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 21, 5)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 21, 7)) +>as : Symbol(as, Decl(nonInferrableTypePropagation2.ts, 21, 53)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 21, 5)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 21, 7)) + + (predicate: Predicate): (bs: ReadonlyArray) => ReadonlyArray +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 22, 5)) +>predicate : Symbol(predicate, Decl(nonInferrableTypePropagation2.ts, 22, 8)) +>Predicate : Symbol(Predicate, Decl(nonInferrableTypePropagation2.ts, 0, 0)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 22, 5)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 22, 35)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 22, 5)) +>bs : Symbol(bs, Decl(nonInferrableTypePropagation2.ts, 22, 48)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 22, 35)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 22, 35)) + + (predicate: Predicate): (as: ReadonlyArray) => ReadonlyArray +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 23, 5)) +>predicate : Symbol(predicate, Decl(nonInferrableTypePropagation2.ts, 23, 8)) +>Predicate : Symbol(Predicate, Decl(nonInferrableTypePropagation2.ts, 0, 0)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 23, 5)) +>as : Symbol(as, Decl(nonInferrableTypePropagation2.ts, 23, 35)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 23, 5)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 23, 5)) + +}; + +declare function pipe(a: A, ab: (a: A) => B): B; +>pipe : Symbol(pipe, Decl(nonInferrableTypePropagation2.ts, 24, 2)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 26, 22)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 26, 24)) +>a : Symbol(a, Decl(nonInferrableTypePropagation2.ts, 26, 28)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 26, 22)) +>ab : Symbol(ab, Decl(nonInferrableTypePropagation2.ts, 26, 33)) +>a : Symbol(a, Decl(nonInferrableTypePropagation2.ts, 26, 39)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 26, 22)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 26, 24)) +>B : Symbol(B, Decl(nonInferrableTypePropagation2.ts, 26, 24)) + +declare function exists(predicate: Predicate): (ma: Either) => boolean; +>exists : Symbol(exists, Decl(nonInferrableTypePropagation2.ts, 26, 54)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 27, 24)) +>predicate : Symbol(predicate, Decl(nonInferrableTypePropagation2.ts, 27, 27)) +>Predicate : Symbol(Predicate, Decl(nonInferrableTypePropagation2.ts, 0, 0)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 27, 24)) +>E : Symbol(E, Decl(nonInferrableTypePropagation2.ts, 27, 54)) +>ma : Symbol(ma, Decl(nonInferrableTypePropagation2.ts, 27, 57)) +>Either : Symbol(Either, Decl(nonInferrableTypePropagation2.ts, 12, 1)) +>E : Symbol(E, Decl(nonInferrableTypePropagation2.ts, 27, 54)) +>A : Symbol(A, Decl(nonInferrableTypePropagation2.ts, 27, 24)) + +declare const es: Either[]; +>es : Symbol(es, Decl(nonInferrableTypePropagation2.ts, 29, 13)) +>Either : Symbol(Either, Decl(nonInferrableTypePropagation2.ts, 12, 1)) + +const x = pipe(es, filter(exists((n) => n > 0))) +>x : Symbol(x, Decl(nonInferrableTypePropagation2.ts, 30, 5)) +>pipe : Symbol(pipe, Decl(nonInferrableTypePropagation2.ts, 24, 2)) +>es : Symbol(es, Decl(nonInferrableTypePropagation2.ts, 29, 13)) +>filter : Symbol(filter, Decl(nonInferrableTypePropagation2.ts, 20, 13)) +>exists : Symbol(exists, Decl(nonInferrableTypePropagation2.ts, 26, 54)) +>n : Symbol(n, Decl(nonInferrableTypePropagation2.ts, 30, 34)) +>n : Symbol(n, Decl(nonInferrableTypePropagation2.ts, 30, 34)) + diff --git a/tests/baselines/reference/nonInferrableTypePropagation2.types b/tests/baselines/reference/nonInferrableTypePropagation2.types new file mode 100644 index 0000000000000..e30463459942b --- /dev/null +++ b/tests/baselines/reference/nonInferrableTypePropagation2.types @@ -0,0 +1,76 @@ +=== tests/cases/compiler/nonInferrableTypePropagation2.ts === +export interface Predicate { + (a: A): boolean +>a : A +} + +interface Left { + readonly _tag: 'Left' +>_tag : "Left" + + readonly left: E +>left : E +} + +interface Right { + readonly _tag: 'Right' +>_tag : "Right" + + readonly right: A +>right : A +} + +type Either = Left | Right; +>Either : Either + +interface Refinement { + (a: A): a is B +>a : A +} + +declare const filter: { +>filter : { (refinement: Refinement): (as: readonly A[]) => readonly B[]; (predicate: Predicate): (bs: readonly B[]) => readonly B[]; (predicate: Predicate): (as: readonly A[]) => readonly A[]; } + + (refinement: Refinement): (as: ReadonlyArray) => ReadonlyArray +>refinement : Refinement +>as : readonly A[] + + (predicate: Predicate): (bs: ReadonlyArray) => ReadonlyArray +>predicate : Predicate +>bs : readonly B[] + + (predicate: Predicate): (as: ReadonlyArray) => ReadonlyArray +>predicate : Predicate +>as : readonly A[] + +}; + +declare function pipe(a: A, ab: (a: A) => B): B; +>pipe : (a: A, ab: (a: A) => B) => B +>a : A +>ab : (a: A) => B +>a : A + +declare function exists(predicate: Predicate): (ma: Either) => boolean; +>exists : (predicate: Predicate) => (ma: Either) => boolean +>predicate : Predicate +>ma : Either + +declare const es: Either[]; +>es : Either[] + +const x = pipe(es, filter(exists((n) => n > 0))) +>x : readonly Either[] +>pipe(es, filter(exists((n) => n > 0))) : readonly Either[] +>pipe : (a: A, ab: (a: A) => B) => B +>es : Either[] +>filter(exists((n) => n > 0)) : (as: readonly Either[]) => readonly Either[] +>filter : { (refinement: Refinement): (as: readonly A[]) => readonly B[]; (predicate: Predicate): (bs: readonly B[]) => readonly B[]; (predicate: Predicate): (as: readonly A[]) => readonly A[]; } +>exists((n) => n > 0) : (ma: Either) => boolean +>exists : (predicate: Predicate) => (ma: Either) => boolean +>(n) => n > 0 : (n: number) => boolean +>n : number +>n > 0 : boolean +>n : number +>0 : 0 + diff --git a/tests/cases/compiler/nonInferrableTypePropagation1.ts b/tests/cases/compiler/nonInferrableTypePropagation1.ts new file mode 100644 index 0000000000000..d0bf10f802906 --- /dev/null +++ b/tests/cases/compiler/nonInferrableTypePropagation1.ts @@ -0,0 +1,29 @@ +// @strict: true + +type Op = (thing: Thing) => Thing; +type Thing = { + value: T; + pipe( + opA: Op, + opB: Op, + ): Thing; +}; +type Box = { data: V }; + +declare const thing: Thing; + +declare function map(project: (value: T) => R): Op; +declare function tap(next: (value: T) => void): Op; +declare function box(data: V): Box; +declare function createAndUnbox(factory: () => Thing>): Thing; +declare function log(value: any): void; + +const result1 = createAndUnbox(() => thing.pipe( + map((data) => box(data)), + tap((v) => log(v)), +)); + +const result2 = createAndUnbox(() => thing.pipe( + tap((v) => log(v)), + map((data) => box(data)), +)); diff --git a/tests/cases/compiler/nonInferrableTypePropagation2.ts b/tests/cases/compiler/nonInferrableTypePropagation2.ts new file mode 100644 index 0000000000000..832323f05dff0 --- /dev/null +++ b/tests/cases/compiler/nonInferrableTypePropagation2.ts @@ -0,0 +1,33 @@ +// @strict: true + +export interface Predicate { + (a: A): boolean +} + +interface Left { + readonly _tag: 'Left' + readonly left: E +} + +interface Right { + readonly _tag: 'Right' + readonly right: A +} + +type Either = Left | Right; + +interface Refinement { + (a: A): a is B +} + +declare const filter: { + (refinement: Refinement): (as: ReadonlyArray) => ReadonlyArray + (predicate: Predicate): (bs: ReadonlyArray) => ReadonlyArray + (predicate: Predicate): (as: ReadonlyArray) => ReadonlyArray +}; + +declare function pipe(a: A, ab: (a: A) => B): B; +declare function exists(predicate: Predicate): (ma: Either) => boolean; + +declare const es: Either[]; +const x = pipe(es, filter(exists((n) => n > 0)))