Properly propagate ObjectFlags.NonInferrableType, clean up non-inferrable code paths (#49887)

This commit is contained in:
Jake Bailey 2022-07-14 18:33:09 -07:00 committed by GitHub
parent 4902860302
commit cf3af3febd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 637 additions and 39 deletions

View File

@ -785,11 +785,10 @@ namespace ts {
const errorTypes = new Map<string, Type>();
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<never> (where never is silentNeverType), Box<never> 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);
}
@ -31271,7 +31274,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);
@ -31906,8 +31909,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);

View File

@ -0,0 +1,34 @@
//// [nonInferrableTypePropagation1.ts]
type Op<I, O> = (thing: Thing<I>) => Thing<O>;
type Thing<T> = {
value: T;
pipe<A, B>(
opA: Op<T, A>,
opB: Op<A, B>,
): Thing<B>;
};
type Box<V> = { data: V };
declare const thing: Thing<number>;
declare function map<T, R>(project: (value: T) => R): Op<T, R>;
declare function tap<T>(next: (value: T) => void): Op<T, T>;
declare function box<V>(data: V): Box<V>;
declare function createAndUnbox<V>(factory: () => Thing<V | Box<V>>): Thing<V>;
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); })); });

View File

@ -0,0 +1,138 @@
=== tests/cases/compiler/nonInferrableTypePropagation1.ts ===
type Op<I, O> = (thing: Thing<I>) => Thing<O>;
>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<T> = {
>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<A, B>(
>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<T, A>,
>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<A, B>,
>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<B>;
>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46))
>B : Symbol(B, Decl(nonInferrableTypePropagation1.ts, 3, 11))
};
type Box<V> = { 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<number>;
>thing : Symbol(thing, Decl(nonInferrableTypePropagation1.ts, 10, 13))
>Thing : Symbol(Thing, Decl(nonInferrableTypePropagation1.ts, 0, 46))
declare function map<T, R>(project: (value: T) => R): Op<T, R>;
>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<T>(next: (value: T) => void): Op<T, T>;
>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<V>(data: V): Box<V>;
>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<V>(factory: () => Thing<V | Box<V>>): Thing<V>;
>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))
));

View File

@ -0,0 +1,111 @@
=== tests/cases/compiler/nonInferrableTypePropagation1.ts ===
type Op<I, O> = (thing: Thing<I>) => Thing<O>;
>Op : Op<I, O>
>thing : Thing<I>
type Thing<T> = {
>Thing : Thing<T>
value: T;
>value : T
pipe<A, B>(
>pipe : <A, B>(opA: Op<T, A>, opB: Op<A, B>) => Thing<B>
opA: Op<T, A>,
>opA : Op<T, A>
opB: Op<A, B>,
>opB : Op<A, B>
): Thing<B>;
};
type Box<V> = { data: V };
>Box : Box<V>
>data : V
declare const thing: Thing<number>;
>thing : Thing<number>
declare function map<T, R>(project: (value: T) => R): Op<T, R>;
>map : <T, R>(project: (value: T) => R) => Op<T, R>
>project : (value: T) => R
>value : T
declare function tap<T>(next: (value: T) => void): Op<T, T>;
>tap : <T>(next: (value: T) => void) => Op<T, T>
>next : (value: T) => void
>value : T
declare function box<V>(data: V): Box<V>;
>box : <V>(data: V) => Box<V>
>data : V
declare function createAndUnbox<V>(factory: () => Thing<V | Box<V>>): Thing<V>;
>createAndUnbox : <V>(factory: () => Thing<V | Box<V>>) => Thing<V>
>factory : () => Thing<V | Box<V>>
declare function log(value: any): void;
>log : (value: any) => void
>value : any
const result1 = createAndUnbox(() => thing.pipe(
>result1 : Thing<number>
>createAndUnbox(() => thing.pipe( map((data) => box(data)), tap((v) => log(v)),)) : Thing<number>
>createAndUnbox : <V>(factory: () => Thing<V | Box<V>>) => Thing<V>
>() => thing.pipe( map((data) => box(data)), tap((v) => log(v)),) : () => Thing<Box<number>>
>thing.pipe( map((data) => box(data)), tap((v) => log(v)),) : Thing<Box<number>>
>thing.pipe : <A, B>(opA: Op<number, A>, opB: Op<A, B>) => Thing<B>
>thing : Thing<number>
>pipe : <A, B>(opA: Op<number, A>, opB: Op<A, B>) => Thing<B>
map((data) => box(data)),
>map((data) => box(data)) : Op<number, Box<number>>
>map : <T, R>(project: (value: T) => R) => Op<T, R>
>(data) => box(data) : (data: number) => Box<number>
>data : number
>box(data) : Box<number>
>box : <V>(data: V) => Box<V>
>data : number
tap((v) => log(v)),
>tap((v) => log(v)) : Op<Box<number>, Box<number>>
>tap : <T>(next: (value: T) => void) => Op<T, T>
>(v) => log(v) : (v: Box<number>) => void
>v : Box<number>
>log(v) : void
>log : (value: any) => void
>v : Box<number>
));
const result2 = createAndUnbox(() => thing.pipe(
>result2 : Thing<number>
>createAndUnbox(() => thing.pipe( tap((v) => log(v)), map((data) => box(data)),)) : Thing<number>
>createAndUnbox : <V>(factory: () => Thing<V | Box<V>>) => Thing<V>
>() => thing.pipe( tap((v) => log(v)), map((data) => box(data)),) : () => Thing<Box<number>>
>thing.pipe( tap((v) => log(v)), map((data) => box(data)),) : Thing<Box<number>>
>thing.pipe : <A, B>(opA: Op<number, A>, opB: Op<A, B>) => Thing<B>
>thing : Thing<number>
>pipe : <A, B>(opA: Op<number, A>, opB: Op<A, B>) => Thing<B>
tap((v) => log(v)),
>tap((v) => log(v)) : Op<number, number>
>tap : <T>(next: (value: T) => void) => Op<T, T>
>(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<number, Box<number>>
>map : <T, R>(project: (value: T) => R) => Op<T, R>
>(data) => box(data) : (data: number) => Box<number>
>data : number
>box(data) : Box<number>
>box : <V>(data: V) => Box<V>
>data : number
));

View File

@ -0,0 +1,38 @@
//// [nonInferrableTypePropagation2.ts]
export interface Predicate<A> {
(a: A): boolean
}
interface Left<E> {
readonly _tag: 'Left'
readonly left: E
}
interface Right<A> {
readonly _tag: 'Right'
readonly right: A
}
type Either<E, A> = Left<E> | Right<A>;
interface Refinement<A, B extends A> {
(a: A): a is B
}
declare const filter: {
<A, B extends A>(refinement: Refinement<A, B>): (as: ReadonlyArray<A>) => ReadonlyArray<B>
<A>(predicate: Predicate<A>): <B extends A>(bs: ReadonlyArray<B>) => ReadonlyArray<B>
<A>(predicate: Predicate<A>): (as: ReadonlyArray<A>) => ReadonlyArray<A>
};
declare function pipe<A, B>(a: A, ab: (a: A) => B): B;
declare function exists<A>(predicate: Predicate<A>): <E>(ma: Either<E, A>) => boolean;
declare const es: Either<string, number>[];
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; })));

View File

@ -0,0 +1,136 @@
=== tests/cases/compiler/nonInferrableTypePropagation2.ts ===
export interface Predicate<A> {
>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<E> {
>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<A> {
>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<E, A> = Left<E> | Right<A>;
>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<A, B extends A> {
>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))
<A, B extends A>(refinement: Refinement<A, B>): (as: ReadonlyArray<A>) => ReadonlyArray<B>
>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))
<A>(predicate: Predicate<A>): <B extends A>(bs: ReadonlyArray<B>) => ReadonlyArray<B>
>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))
<A>(predicate: Predicate<A>): (as: ReadonlyArray<A>) => ReadonlyArray<A>
>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, B>(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<A>(predicate: Predicate<A>): <E>(ma: Either<E, A>) => 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<string, number>[];
>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))

View File

@ -0,0 +1,76 @@
=== tests/cases/compiler/nonInferrableTypePropagation2.ts ===
export interface Predicate<A> {
(a: A): boolean
>a : A
}
interface Left<E> {
readonly _tag: 'Left'
>_tag : "Left"
readonly left: E
>left : E
}
interface Right<A> {
readonly _tag: 'Right'
>_tag : "Right"
readonly right: A
>right : A
}
type Either<E, A> = Left<E> | Right<A>;
>Either : Either<E, A>
interface Refinement<A, B extends A> {
(a: A): a is B
>a : A
}
declare const filter: {
>filter : { <A, B extends A>(refinement: Refinement<A, B>): (as: readonly A[]) => readonly B[]; <A>(predicate: Predicate<A>): <B extends A>(bs: readonly B[]) => readonly B[]; <A>(predicate: Predicate<A>): (as: readonly A[]) => readonly A[]; }
<A, B extends A>(refinement: Refinement<A, B>): (as: ReadonlyArray<A>) => ReadonlyArray<B>
>refinement : Refinement<A, B>
>as : readonly A[]
<A>(predicate: Predicate<A>): <B extends A>(bs: ReadonlyArray<B>) => ReadonlyArray<B>
>predicate : Predicate<A>
>bs : readonly B[]
<A>(predicate: Predicate<A>): (as: ReadonlyArray<A>) => ReadonlyArray<A>
>predicate : Predicate<A>
>as : readonly A[]
};
declare function pipe<A, B>(a: A, ab: (a: A) => B): B;
>pipe : <A, B>(a: A, ab: (a: A) => B) => B
>a : A
>ab : (a: A) => B
>a : A
declare function exists<A>(predicate: Predicate<A>): <E>(ma: Either<E, A>) => boolean;
>exists : <A>(predicate: Predicate<A>) => <E>(ma: Either<E, A>) => boolean
>predicate : Predicate<A>
>ma : Either<E, A>
declare const es: Either<string, number>[];
>es : Either<string, number>[]
const x = pipe(es, filter(exists((n) => n > 0)))
>x : readonly Either<string, number>[]
>pipe(es, filter(exists((n) => n > 0))) : readonly Either<string, number>[]
>pipe : <A, B>(a: A, ab: (a: A) => B) => B
>es : Either<string, number>[]
>filter(exists((n) => n > 0)) : (as: readonly Either<string, number>[]) => readonly Either<string, number>[]
>filter : { <A, B extends A>(refinement: Refinement<A, B>): (as: readonly A[]) => readonly B[]; <A>(predicate: Predicate<A>): <B extends A>(bs: readonly B[]) => readonly B[]; <A>(predicate: Predicate<A>): (as: readonly A[]) => readonly A[]; }
>exists((n) => n > 0) : <E>(ma: Either<E, number>) => boolean
>exists : <A>(predicate: Predicate<A>) => <E>(ma: Either<E, A>) => boolean
>(n) => n > 0 : (n: number) => boolean
>n : number
>n > 0 : boolean
>n : number
>0 : 0

View File

@ -0,0 +1,29 @@
// @strict: true
type Op<I, O> = (thing: Thing<I>) => Thing<O>;
type Thing<T> = {
value: T;
pipe<A, B>(
opA: Op<T, A>,
opB: Op<A, B>,
): Thing<B>;
};
type Box<V> = { data: V };
declare const thing: Thing<number>;
declare function map<T, R>(project: (value: T) => R): Op<T, R>;
declare function tap<T>(next: (value: T) => void): Op<T, T>;
declare function box<V>(data: V): Box<V>;
declare function createAndUnbox<V>(factory: () => Thing<V | Box<V>>): Thing<V>;
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)),
));

View File

@ -0,0 +1,33 @@
// @strict: true
export interface Predicate<A> {
(a: A): boolean
}
interface Left<E> {
readonly _tag: 'Left'
readonly left: E
}
interface Right<A> {
readonly _tag: 'Right'
readonly right: A
}
type Either<E, A> = Left<E> | Right<A>;
interface Refinement<A, B extends A> {
(a: A): a is B
}
declare const filter: {
<A, B extends A>(refinement: Refinement<A, B>): (as: ReadonlyArray<A>) => ReadonlyArray<B>
<A>(predicate: Predicate<A>): <B extends A>(bs: ReadonlyArray<B>) => ReadonlyArray<B>
<A>(predicate: Predicate<A>): (as: ReadonlyArray<A>) => ReadonlyArray<A>
};
declare function pipe<A, B>(a: A, ab: (a: A) => B): B;
declare function exists<A>(predicate: Predicate<A>): <E>(ma: Either<E, A>) => boolean;
declare const es: Either<string, number>[];
const x = pipe(es, filter(exists((n) => n > 0)))