diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eb033794aee56..4f11923247657 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -79,8 +79,7 @@ module ts { let emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - let inferenceFailureType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - + let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false); let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false); @@ -3514,6 +3513,7 @@ module ts { return t => { for (let i = 0; i < context.typeParameters.length; i++) { if (t === context.typeParameters[i]) { + context.inferences[i].isFixed = true; return getInferredType(context, i); } } @@ -4372,8 +4372,11 @@ module ts { } function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void { + // The downfallType/bestSupertypeDownfallType is the first type that caused a particular candidate + // to not be the common supertype. So if it weren't for this one downfallType (and possibly others), + // the type in question could have been the common supertype. let bestSupertype: Type; - let bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype + let bestSupertypeDownfallType: Type; let bestSupertypeScore = 0; for (let i = 0; i < types.length; i++) { @@ -4388,6 +4391,8 @@ module ts { } } + Debug.assert(!!downfallType, "If there is no common supertype, each type should have a downfallType"); + if (score > bestSupertypeScore) { bestSupertype = types[i]; bestSupertypeDownfallType = downfallType; @@ -4570,13 +4575,12 @@ module ts { function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext { let inferences: TypeInferences[] = []; for (let unused of typeParameters) { - inferences.push({ primary: undefined, secondary: undefined }); + inferences.push({ primary: undefined, secondary: undefined, isFixed: false }); } return { - typeParameters: typeParameters, - inferUnionTypes: inferUnionTypes, - inferenceCount: 0, - inferences: inferences, + typeParameters, + inferUnionTypes, + inferences, inferredTypes: new Array(typeParameters.length), }; } @@ -4622,11 +4626,21 @@ module ts { for (let i = 0; i < typeParameters.length; i++) { if (target === typeParameters[i]) { let inferences = context.inferences[i]; - let candidates = inferiority ? - inferences.secondary || (inferences.secondary = []) : - inferences.primary || (inferences.primary = []); - if (!contains(candidates, source)) candidates.push(source); - break; + if (!inferences.isFixed) { + // Any inferences that are made to a type parameter in a union type are inferior + // to inferences made to a flat (non-union) type. This is because if we infer to + // T | string[], we really don't know if we should be inferring to T or not (because + // the correct constituent on the target side could be string[]). Therefore, we put + // such inferior inferences into a secondary bucket, and only use them if the primary + // bucket is empty. + let candidates = inferiority ? + inferences.secondary || (inferences.secondary = []) : + inferences.primary || (inferences.primary = []); + if (!contains(candidates, source)) { + candidates.push(source); + } + } + return; } } } @@ -4732,21 +4746,35 @@ module ts { function getInferredType(context: InferenceContext, index: number): Type { let inferredType = context.inferredTypes[index]; + let inferenceSucceeded: boolean; if (!inferredType) { let inferences = getInferenceCandidates(context, index); if (inferences.length) { - // Infer widened union or supertype, or the undefined type for no common supertype + // Infer widened union or supertype, or the unknown type for no common supertype let unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences); - inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType; + inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType; + inferenceSucceeded = !!unionOrSuperType; } else { - // Infer the empty object type when no inferences were made + // Infer the empty object type when no inferences were made. It is important to remember that + // in this case, inference still succeeds, meaning there is no error for not having inference + // candidates. An inference error only occurs when there are *conflicting* candidates, i.e. + // candidates with no common supertype. inferredType = emptyObjectType; + inferenceSucceeded = true; } - if (inferredType !== inferenceFailureType) { + + // Only do the constraint check if inference succeeded (to prevent cascading errors) + if (inferenceSucceeded) { let constraint = getConstraintOfTypeParameter(context.typeParameters[index]); inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType; } + else if (context.failedTypeParameterIndex === undefined || context.failedTypeParameterIndex > index) { + // If inference failed, it is necessary to record the index of the failed type parameter (the one we are on). + // It might be that inference has already failed on a later type parameter on a previous call to inferTypeArguments. + // So if this failure is on preceding type parameter, this type parameter is the new failure index. + context.failedTypeParameterIndex = index; + } context.inferredTypes[index] = inferredType; } return inferredType; @@ -6343,11 +6371,32 @@ module ts { return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[]): InferenceContext { + function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): void { let typeParameters = signature.typeParameters; - let context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false); let inferenceMapper = createInferenceMapper(context); + // Clear out all the inference results from the last time inferTypeArguments was called on this context + for (let i = 0; i < typeParameters.length; i++) { + // As an optimization, we don't have to clear (and later recompute) inferred types + // for type parameters that have already been fixed on the previous call to inferTypeArguments. + // It would be just as correct to reset all of them. But then we'd be repeating the same work + // for the type parameters that were fixed, namely the work done by getInferredType. + if (!context.inferences[i].isFixed) { + context.inferredTypes[i] = undefined; + } + } + + // On this call to inferTypeArguments, we may get more inferences for certain type parameters that were not + // fixed last time. This means that a type parameter that failed inference last time may succeed this time, + // or vice versa. Therefore, the failedTypeParameterIndex is useless if it points to an unfixed type parameter, + // because it may change. So here we reset it. However, getInferredType will not revisit any type parameters + // that were previously fixed. So if a fixed type parameter failed previously, it will fail again because + // it will contain the exact same set of inferences. So if we reset the index from a fixed type parameter, + // we will lose information that we won't recover this time around. + if (context.failedTypeParameterIndex !== undefined && !context.inferences[context.failedTypeParameterIndex].isFixed) { + context.failedTypeParameterIndex = undefined; + } + // We perform two passes over the arguments. In the first pass we infer from all arguments, but use // wildcards for all context sensitive function expressions. for (let i = 0; i < args.length; i++) { @@ -6382,18 +6431,7 @@ module ts { } } - let inferredTypes = getInferredTypes(context); - // Inference has failed if the inferenceFailureType type is in list of inferences - context.failedTypeParameterIndex = indexOf(inferredTypes, inferenceFailureType); - - // Wipe out the inferenceFailureType from the array so that error recovery can work properly - for (let i = 0; i < inferredTypes.length; i++) { - if (inferredTypes[i] === inferenceFailureType) { - inferredTypes[i] = unknownType; - } - } - - return context; + getInferredTypes(context); } function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean { @@ -6627,15 +6665,17 @@ module ts { return resolveErrorCall(node); function chooseOverload(candidates: Signature[], relation: Map) { - for (let current of candidates) { - if (!hasCorrectArity(node, args, current)) { + for (let originalCandidate of candidates) { + if (!hasCorrectArity(node, args, originalCandidate)) { continue; } - - let originalCandidate = current; - let inferenceResult: InferenceContext; + let candidate: Signature; let typeArgumentsAreValid: boolean; + let inferenceContext = originalCandidate.typeParameters + ? createInferenceContext(originalCandidate.typeParameters, /*inferUnionTypes*/ false) + : undefined; + while (true) { candidate = originalCandidate; if (candidate.typeParameters) { @@ -6645,9 +6685,9 @@ module ts { typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false) } else { - inferenceResult = inferTypeArguments(candidate, args, excludeArgument); - typeArgumentsAreValid = inferenceResult.failedTypeParameterIndex < 0; - typeArgumentTypes = inferenceResult.inferredTypes; + inferTypeArguments(candidate, args, excludeArgument, inferenceContext); + typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex === undefined; + typeArgumentTypes = inferenceContext.inferredTypes; } if (!typeArgumentsAreValid) { break; @@ -6677,7 +6717,7 @@ module ts { else { candidateForTypeArgumentError = originalCandidate; if (!typeArguments) { - resultOfFailedInference = inferenceResult; + resultOfFailedInference = inferenceContext; } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 91ad490e50f2b..87d219c2e844a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1487,11 +1487,15 @@ module ts { (t: Type): Type; } + // @internal export interface TypeInferences { primary: Type[]; // Inferences made directly to a type parameter secondary: Type[]; // Inferences made to a type parameter in a union type + isFixed: boolean; // Whether the type parameter is fixed, as defined in section 4.12.2 of the TypeScript spec + // If a type parameter is fixed, no more inferences can be made for the type parameter } + // @internal export interface InferenceContext { typeParameters: TypeParameter[]; // Type parameters for which inferences are made inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType) diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index b03081d721d09..575c2bdaf36d1 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1176,17 +1176,6 @@ declare module "typescript" { interface TypeMapper { (t: Type): Type; } - interface TypeInferences { - primary: Type[]; - secondary: Type[]; - } - interface InferenceContext { - typeParameters: TypeParameter[]; - inferUnionTypes: boolean; - inferences: TypeInferences[]; - inferredTypes: Type[]; - failedTypeParameterIndex?: number; - } interface DiagnosticMessage { key: string; category: DiagnosticCategory; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index e14cd96d2bcbb..336d70aa1a196 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -3769,38 +3769,6 @@ declare module "typescript" { >t : Type >Type : Type >Type : Type - } - interface TypeInferences { ->TypeInferences : TypeInferences - - primary: Type[]; ->primary : Type[] ->Type : Type - - secondary: Type[]; ->secondary : Type[] ->Type : Type - } - interface InferenceContext { ->InferenceContext : InferenceContext - - typeParameters: TypeParameter[]; ->typeParameters : TypeParameter[] ->TypeParameter : TypeParameter - - inferUnionTypes: boolean; ->inferUnionTypes : boolean - - inferences: TypeInferences[]; ->inferences : TypeInferences[] ->TypeInferences : TypeInferences - - inferredTypes: Type[]; ->inferredTypes : Type[] ->Type : Type - - failedTypeParameterIndex?: number; ->failedTypeParameterIndex : number } interface DiagnosticMessage { >DiagnosticMessage : DiagnosticMessage diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 313d03f14d02b..e7145e2407059 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1207,17 +1207,6 @@ declare module "typescript" { interface TypeMapper { (t: Type): Type; } - interface TypeInferences { - primary: Type[]; - secondary: Type[]; - } - interface InferenceContext { - typeParameters: TypeParameter[]; - inferUnionTypes: boolean; - inferences: TypeInferences[]; - inferredTypes: Type[]; - failedTypeParameterIndex?: number; - } interface DiagnosticMessage { key: string; category: DiagnosticCategory; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 538cab1382a2f..a40848b9e4c63 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -3915,38 +3915,6 @@ declare module "typescript" { >t : Type >Type : Type >Type : Type - } - interface TypeInferences { ->TypeInferences : TypeInferences - - primary: Type[]; ->primary : Type[] ->Type : Type - - secondary: Type[]; ->secondary : Type[] ->Type : Type - } - interface InferenceContext { ->InferenceContext : InferenceContext - - typeParameters: TypeParameter[]; ->typeParameters : TypeParameter[] ->TypeParameter : TypeParameter - - inferUnionTypes: boolean; ->inferUnionTypes : boolean - - inferences: TypeInferences[]; ->inferences : TypeInferences[] ->TypeInferences : TypeInferences - - inferredTypes: Type[]; ->inferredTypes : Type[] ->Type : Type - - failedTypeParameterIndex?: number; ->failedTypeParameterIndex : number } interface DiagnosticMessage { >DiagnosticMessage : DiagnosticMessage diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index e34e271c6a1d5..da8fe979d1700 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1208,17 +1208,6 @@ declare module "typescript" { interface TypeMapper { (t: Type): Type; } - interface TypeInferences { - primary: Type[]; - secondary: Type[]; - } - interface InferenceContext { - typeParameters: TypeParameter[]; - inferUnionTypes: boolean; - inferences: TypeInferences[]; - inferredTypes: Type[]; - failedTypeParameterIndex?: number; - } interface DiagnosticMessage { key: string; category: DiagnosticCategory; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 663dc59c8430a..b694678d4cb9a 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -3865,38 +3865,6 @@ declare module "typescript" { >t : Type >Type : Type >Type : Type - } - interface TypeInferences { ->TypeInferences : TypeInferences - - primary: Type[]; ->primary : Type[] ->Type : Type - - secondary: Type[]; ->secondary : Type[] ->Type : Type - } - interface InferenceContext { ->InferenceContext : InferenceContext - - typeParameters: TypeParameter[]; ->typeParameters : TypeParameter[] ->TypeParameter : TypeParameter - - inferUnionTypes: boolean; ->inferUnionTypes : boolean - - inferences: TypeInferences[]; ->inferences : TypeInferences[] ->TypeInferences : TypeInferences - - inferredTypes: Type[]; ->inferredTypes : Type[] ->Type : Type - - failedTypeParameterIndex?: number; ->failedTypeParameterIndex : number } interface DiagnosticMessage { >DiagnosticMessage : DiagnosticMessage diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index ff762af1d9e8b..f380994eba888 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1245,17 +1245,6 @@ declare module "typescript" { interface TypeMapper { (t: Type): Type; } - interface TypeInferences { - primary: Type[]; - secondary: Type[]; - } - interface InferenceContext { - typeParameters: TypeParameter[]; - inferUnionTypes: boolean; - inferences: TypeInferences[]; - inferredTypes: Type[]; - failedTypeParameterIndex?: number; - } interface DiagnosticMessage { key: string; category: DiagnosticCategory; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 8ea691d2d0d61..06329de5c961f 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -4038,38 +4038,6 @@ declare module "typescript" { >t : Type >Type : Type >Type : Type - } - interface TypeInferences { ->TypeInferences : TypeInferences - - primary: Type[]; ->primary : Type[] ->Type : Type - - secondary: Type[]; ->secondary : Type[] ->Type : Type - } - interface InferenceContext { ->InferenceContext : InferenceContext - - typeParameters: TypeParameter[]; ->typeParameters : TypeParameter[] ->TypeParameter : TypeParameter - - inferUnionTypes: boolean; ->inferUnionTypes : boolean - - inferences: TypeInferences[]; ->inferences : TypeInferences[] ->TypeInferences : TypeInferences - - inferredTypes: Type[]; ->inferredTypes : Type[] ->Type : Type - - failedTypeParameterIndex?: number; ->failedTypeParameterIndex : number } interface DiagnosticMessage { >DiagnosticMessage : DiagnosticMessage diff --git a/tests/baselines/reference/typeParameterFixingWithConstraints.js b/tests/baselines/reference/typeParameterFixingWithConstraints.js new file mode 100644 index 0000000000000..49b2c48fbe22b --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithConstraints.js @@ -0,0 +1,21 @@ +//// [typeParameterFixingWithConstraints.ts] +interface IBar { + [barId: string]: any; +} + +interface IFoo { + foo(bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar): TBar; +} + +var foo: IFoo; +foo.foo({ bar: null }, bar => null, bar => null); + +//// [typeParameterFixingWithConstraints.js] +var foo; +foo.foo({ + bar: null +}, function (bar) { + return null; +}, function (bar) { + return null; +}); diff --git a/tests/baselines/reference/typeParameterFixingWithConstraints.types b/tests/baselines/reference/typeParameterFixingWithConstraints.types new file mode 100644 index 0000000000000..c15f22fc974ba --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithConstraints.types @@ -0,0 +1,44 @@ +=== tests/cases/compiler/typeParameterFixingWithConstraints.ts === +interface IBar { +>IBar : IBar + + [barId: string]: any; +>barId : string +} + +interface IFoo { +>IFoo : IFoo + + foo(bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar): TBar; +>foo : (bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar +>TBar : TBar +>IBar : IBar +>bar : TBar +>TBar : TBar +>bar1 : (bar: TBar) => TBar +>bar : TBar +>TBar : TBar +>TBar : TBar +>bar2 : (bar: TBar) => TBar +>bar : TBar +>TBar : TBar +>TBar : TBar +>TBar : TBar +} + +var foo: IFoo; +>foo : IFoo +>IFoo : IFoo + +foo.foo({ bar: null }, bar => null, bar => null); +>foo.foo({ bar: null }, bar => null, bar => null) : IBar +>foo.foo : (bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar +>foo : IFoo +>foo : (bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar +>{ bar: null } : { [x: string]: null; bar: null; } +>bar : null +>bar => null : (bar: IBar) => any +>bar : IBar +>bar => null : (bar: IBar) => any +>bar : IBar + diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments.js b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments.js new file mode 100644 index 0000000000000..170bd711b6148 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments.js @@ -0,0 +1,28 @@ +//// [typeParameterFixingWithContextSensitiveArguments.ts] +function f(y: T, f: (x: T) => U, x: T): [T, U] { return [y, f(x)]; } +interface A { a: A; } +interface B extends A { b; } + +var a: A, b: B; + +var d = f(b, x => x.a, a); // type [A, A] +var d2 = f(b, x => x.a, null); // type [B, A] +var d3 = f(b, x => x.b, null); // type [B, any] + +//// [typeParameterFixingWithContextSensitiveArguments.js] +function f(y, f, x) { + return [ + y, + f(x) + ]; +} +var a, b; +var d = f(b, function (x) { + return x.a; +}, a); // type [A, A] +var d2 = f(b, function (x) { + return x.a; +}, null); // type [B, A] +var d3 = f(b, function (x) { + return x.b; +}, null); // type [B, any] diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments.types b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments.types new file mode 100644 index 0000000000000..d6bd1b3b271b0 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments.types @@ -0,0 +1,71 @@ +=== tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments.ts === +function f(y: T, f: (x: T) => U, x: T): [T, U] { return [y, f(x)]; } +>f : (y: T, f: (x: T) => U, x: T) => [T, U] +>T : T +>U : U +>y : T +>T : T +>f : (x: T) => U +>x : T +>T : T +>U : U +>x : T +>T : T +>T : T +>U : U +>[y, f(x)] : [T, U] +>y : T +>f(x) : U +>f : (x: T) => U +>x : T + +interface A { a: A; } +>A : A +>a : A +>A : A + +interface B extends A { b; } +>B : B +>A : A +>b : any + +var a: A, b: B; +>a : A +>A : A +>b : B +>B : B + +var d = f(b, x => x.a, a); // type [A, A] +>d : [A, A] +>f(b, x => x.a, a) : [A, A] +>f : (y: T, f: (x: T) => U, x: T) => [T, U] +>b : B +>x => x.a : (x: A) => A +>x : A +>x.a : A +>x : A +>a : A +>a : A + +var d2 = f(b, x => x.a, null); // type [B, A] +>d2 : [B, A] +>f(b, x => x.a, null) : [B, A] +>f : (y: T, f: (x: T) => U, x: T) => [T, U] +>b : B +>x => x.a : (x: B) => A +>x : B +>x.a : A +>x : B +>a : A + +var d3 = f(b, x => x.b, null); // type [B, any] +>d3 : [B, any] +>f(b, x => x.b, null) : [B, any] +>f : (y: T, f: (x: T) => U, x: T) => [T, U] +>b : B +>x => x.b : (x: B) => any +>x : B +>x.b : any +>x : B +>b : any + diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments2.errors.txt b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments2.errors.txt new file mode 100644 index 0000000000000..6a7975b4b6212 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments2.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments2.ts(7,25): error TS2345: Argument of type '(x: A) => A' is not assignable to parameter of type '(x: A) => B'. + Type 'A' is not assignable to type 'B'. + + +==== tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments2.ts (1 errors) ==== + function f(y: T, y1: U, p: (z: U) => T, p1: (x: T) => U): [T, U] { return [y, p1(y)]; } + interface A { a: A; } + interface B extends A { b; } + + var a: A, b: B; + + var d = f(a, b, x => x, x => x); // A => A not assignable to A => B + ~~~~~~ +!!! error TS2345: Argument of type '(x: A) => A' is not assignable to parameter of type '(x: A) => B'. +!!! error TS2345: Type 'A' is not assignable to type 'B'. \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments2.js b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments2.js new file mode 100644 index 0000000000000..1b97f04953e33 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments2.js @@ -0,0 +1,22 @@ +//// [typeParameterFixingWithContextSensitiveArguments2.ts] +function f(y: T, y1: U, p: (z: U) => T, p1: (x: T) => U): [T, U] { return [y, p1(y)]; } +interface A { a: A; } +interface B extends A { b; } + +var a: A, b: B; + +var d = f(a, b, x => x, x => x); // A => A not assignable to A => B + +//// [typeParameterFixingWithContextSensitiveArguments2.js] +function f(y, y1, p, p1) { + return [ + y, + p1(y) + ]; +} +var a, b; +var d = f(a, b, function (x) { + return x; +}, function (x) { + return x; +}); // A => A not assignable to A => B diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments3.errors.txt b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments3.errors.txt new file mode 100644 index 0000000000000..89be3c06c6497 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments3.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments3.ts(7,29): error TS2345: Argument of type '(t2: A) => A' is not assignable to parameter of type '(t2: A) => B'. + Type 'A' is not assignable to type 'B'. + + +==== tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments3.ts (1 errors) ==== + function f(t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U): [T, U] { return [t1, pf2(t1)]; } + interface A { a: A; } + interface B extends A { b: B; } + + var a: A, b: B; + + var d = f(a, b, u2 => u2.b, t2 => t2); + ~~~~~~~~ +!!! error TS2345: Argument of type '(t2: A) => A' is not assignable to parameter of type '(t2: A) => B'. +!!! error TS2345: Type 'A' is not assignable to type 'B'. \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments3.js b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments3.js new file mode 100644 index 0000000000000..4b5370cfc1ce7 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments3.js @@ -0,0 +1,22 @@ +//// [typeParameterFixingWithContextSensitiveArguments3.ts] +function f(t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U): [T, U] { return [t1, pf2(t1)]; } +interface A { a: A; } +interface B extends A { b: B; } + +var a: A, b: B; + +var d = f(a, b, u2 => u2.b, t2 => t2); + +//// [typeParameterFixingWithContextSensitiveArguments3.js] +function f(t1, u1, pf1, pf2) { + return [ + t1, + pf2(t1) + ]; +} +var a, b; +var d = f(a, b, function (u2) { + return u2.b; +}, function (t2) { + return t2; +}); diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments4.js b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments4.js new file mode 100644 index 0000000000000..7efab1f62c5fb --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments4.js @@ -0,0 +1,22 @@ +//// [typeParameterFixingWithContextSensitiveArguments4.ts] +function f(y: T, y1: U, p: (z: U) => T, p1: (x: T) => U): [T, U] { return [y, p1(y)]; } +interface A { a: A; } +interface B extends A { b; } + +var a: A, b: B; + +var d = f(a, b, x => x, x => x); // Type [A, B] + +//// [typeParameterFixingWithContextSensitiveArguments4.js] +function f(y, y1, p, p1) { + return [ + y, + p1(y) + ]; +} +var a, b; +var d = f(a, b, function (x) { + return x; +}, function (x) { + return x; +}); // Type [A, B] diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments4.types b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments4.types new file mode 100644 index 0000000000000..61158ae97384f --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments4.types @@ -0,0 +1,55 @@ +=== tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments4.ts === +function f(y: T, y1: U, p: (z: U) => T, p1: (x: T) => U): [T, U] { return [y, p1(y)]; } +>f : (y: T, y1: U, p: (z: U) => T, p1: (x: T) => U) => [T, U] +>T : T +>U : U +>y : T +>T : T +>y1 : U +>U : U +>p : (z: U) => T +>z : U +>U : U +>T : T +>p1 : (x: T) => U +>x : T +>T : T +>U : U +>T : T +>U : U +>[y, p1(y)] : [T, U] +>y : T +>p1(y) : U +>p1 : (x: T) => U +>y : T + +interface A { a: A; } +>A : A +>a : A +>A : A + +interface B extends A { b; } +>B : B +>A : A +>b : any + +var a: A, b: B; +>a : A +>A : A +>b : B +>B : B + +var d = f(a, b, x => x, x => x); // Type [A, B] +>d : [A, B] +>f(a, b, x => x, x => x) : [A, B] +>f : (y: T, y1: U, p: (z: U) => T, p1: (x: T) => U) => [T, U] +>a : A +>b : B +>x => x : (x: B) => B +>x : B +>x : B +>x => x : (x: A) => any +>x : A +>x : any +>x : A + diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments5.js b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments5.js new file mode 100644 index 0000000000000..7ab2502e02cc8 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments5.js @@ -0,0 +1,22 @@ +//// [typeParameterFixingWithContextSensitiveArguments5.ts] +function f(t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U): [T, U] { return [t1, pf2(t1)]; } +interface A { a: A; } +interface B extends A { b: any; } + +var a: A, b: B; + +var d = f(a, b, u2 => u2.b, t2 => t2); + +//// [typeParameterFixingWithContextSensitiveArguments5.js] +function f(t1, u1, pf1, pf2) { + return [ + t1, + pf2(t1) + ]; +} +var a, b; +var d = f(a, b, function (u2) { + return u2.b; +}, function (t2) { + return t2; +}); diff --git a/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments5.types b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments5.types new file mode 100644 index 0000000000000..3eb7d07bc3ce9 --- /dev/null +++ b/tests/baselines/reference/typeParameterFixingWithContextSensitiveArguments5.types @@ -0,0 +1,56 @@ +=== tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments5.ts === +function f(t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U): [T, U] { return [t1, pf2(t1)]; } +>f : (t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U) => [T, U] +>T : T +>U : U +>t1 : T +>T : T +>u1 : U +>U : U +>pf1 : (u2: U) => T +>u2 : U +>U : U +>T : T +>pf2 : (t2: T) => U +>t2 : T +>T : T +>U : U +>T : T +>U : U +>[t1, pf2(t1)] : [T, U] +>t1 : T +>pf2(t1) : U +>pf2 : (t2: T) => U +>t1 : T + +interface A { a: A; } +>A : A +>a : A +>A : A + +interface B extends A { b: any; } +>B : B +>A : A +>b : any + +var a: A, b: B; +>a : A +>A : A +>b : B +>B : B + +var d = f(a, b, u2 => u2.b, t2 => t2); +>d : [any, B] +>f(a, b, u2 => u2.b, t2 => t2) : [any, B] +>f : (t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U) => [T, U] +>a : A +>b : B +>u2 => u2.b : (u2: B) => any +>u2 : B +>u2.b : any +>u2 : B +>b : any +>t2 => t2 : (t2: any) => any +>t2 : any +>t2 : any + diff --git a/tests/cases/compiler/typeParameterFixingWithConstraints.ts b/tests/cases/compiler/typeParameterFixingWithConstraints.ts new file mode 100644 index 0000000000000..3d8536ab4cfd6 --- /dev/null +++ b/tests/cases/compiler/typeParameterFixingWithConstraints.ts @@ -0,0 +1,10 @@ +interface IBar { + [barId: string]: any; +} + +interface IFoo { + foo(bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar): TBar; +} + +var foo: IFoo; +foo.foo({ bar: null }, bar => null, bar => null); \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments.ts b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments.ts new file mode 100644 index 0000000000000..c05b26fd2fcc5 --- /dev/null +++ b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments.ts @@ -0,0 +1,9 @@ +function f(y: T, f: (x: T) => U, x: T): [T, U] { return [y, f(x)]; } +interface A { a: A; } +interface B extends A { b; } + +var a: A, b: B; + +var d = f(b, x => x.a, a); // type [A, A] +var d2 = f(b, x => x.a, null); // type [B, A] +var d3 = f(b, x => x.b, null); // type [B, any] \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments2.ts b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments2.ts new file mode 100644 index 0000000000000..f4f001c9f2795 --- /dev/null +++ b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments2.ts @@ -0,0 +1,7 @@ +function f(y: T, y1: U, p: (z: U) => T, p1: (x: T) => U): [T, U] { return [y, p1(y)]; } +interface A { a: A; } +interface B extends A { b; } + +var a: A, b: B; + +var d = f(a, b, x => x, x => x); // A => A not assignable to A => B \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments3.ts b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments3.ts new file mode 100644 index 0000000000000..1bf4169624db5 --- /dev/null +++ b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments3.ts @@ -0,0 +1,7 @@ +function f(t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U): [T, U] { return [t1, pf2(t1)]; } +interface A { a: A; } +interface B extends A { b: B; } + +var a: A, b: B; + +var d = f(a, b, u2 => u2.b, t2 => t2); \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments4.ts b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments4.ts new file mode 100644 index 0000000000000..8fa501906b862 --- /dev/null +++ b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments4.ts @@ -0,0 +1,7 @@ +function f(y: T, y1: U, p: (z: U) => T, p1: (x: T) => U): [T, U] { return [y, p1(y)]; } +interface A { a: A; } +interface B extends A { b; } + +var a: A, b: B; + +var d = f(a, b, x => x, x => x); // Type [A, B] \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments5.ts b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments5.ts new file mode 100644 index 0000000000000..a74eb04269229 --- /dev/null +++ b/tests/cases/compiler/typeParameterFixingWithContextSensitiveArguments5.ts @@ -0,0 +1,7 @@ +function f(t1: T, u1: U, pf1: (u2: U) => T, pf2: (t2: T) => U): [T, U] { return [t1, pf2(t1)]; } +interface A { a: A; } +interface B extends A { b: any; } + +var a: A, b: B; + +var d = f(a, b, u2 => u2.b, t2 => t2); \ No newline at end of file