From 544b1772c3e85992b96fda4cc42f36c883983828 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 8 Jul 2015 14:49:41 -0700 Subject: [PATCH 1/7] Fix type parameters every time a parameter is assigned a contextual type --- src/compiler/checker.ts | 71 +++++++++++++++++++++++++++++++---------- src/compiler/types.ts | 3 ++ 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b34952f3a..05174a4315 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4225,7 +4225,7 @@ namespace ts { } function createInferenceMapper(context: InferenceContext): TypeMapper { - return t => { + let mapper: TypeMapper = t => { for (let i = 0; i < context.typeParameters.length; i++) { if (t === context.typeParameters[i]) { context.inferences[i].isFixed = true; @@ -4234,6 +4234,20 @@ namespace ts { } return t; } + + mapper.context = context; + return mapper; + } + + function fixTypeParametersAfterInferringFromContextualParameterTypes(context: InferenceContext): void { + for (let i = 0; i < context.typeParameters.length; i++) { + let typeParameterInfo = context.inferences[i]; + if (typeParameterInfo.fixAfterInferringFromContextualParameterType) { + typeParameterInfo.fixAfterInferringFromContextualParameterType = false; + typeParameterInfo.isFixed = true; + getInferredType(context, i); + } + } } function identityMapper(type: Type): Type { @@ -5397,7 +5411,10 @@ namespace ts { function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext { let inferences: TypeInferences[] = []; for (let unused of typeParameters) { - inferences.push({ primary: undefined, secondary: undefined, isFixed: false }); + inferences.push({ + primary: undefined, secondary: undefined, + isFixed: false, fixAfterInferringFromContextualParameterType: false + }); } return { typeParameters, @@ -5407,7 +5424,7 @@ namespace ts { }; } - function inferTypes(context: InferenceContext, source: Type, target: Type) { + function inferTypes(context: InferenceContext, source: Type, target: Type, inferringFromContextuallyTypedParameter: boolean) { let sourceStack: Type[]; let targetStack: Type[]; let depth = 0; @@ -5446,6 +5463,9 @@ namespace ts { if (!contains(candidates, source)) { candidates.push(source); } + if (inferringFromContextuallyTypedParameter) { + inferences.fixAfterInferringFromContextualParameterType = true; + } } return; } @@ -6698,7 +6718,7 @@ namespace ts { // Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is // used as a special marker for other purposes. function isInferentialContext(mapper: TypeMapper) { - return mapper && mapper !== identityMapper; + return mapper && mapper.context; } // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property @@ -7834,7 +7854,7 @@ namespace ts { let context = createInferenceContext(signature.typeParameters, /*inferUnionTypes*/ true); forEachMatchingParameterType(contextualSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type - inferTypes(context, instantiateType(source, contextualMapper), target); + inferTypes(context, instantiateType(source, contextualMapper), target, false); }); return getSignatureInstantiation(signature, getInferredTypes(context)); } @@ -7884,7 +7904,7 @@ namespace ts { argType = checkExpressionWithContextualType(arg, paramType, mapper); } - inferTypes(context, argType, paramType); + inferTypes(context, argType, paramType, false); } } @@ -7899,7 +7919,7 @@ namespace ts { if (excludeArgument[i] === false) { let arg = args[i]; let paramType = getTypeAtPosition(signature, i); - inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); + inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType, false); } } } @@ -8788,13 +8808,23 @@ namespace ts { let len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0); for (let i = 0; i < len; i++) { let parameter = signature.parameters[i]; - let links = getSymbolLinks(parameter); - links.type = instantiateType(getTypeAtPosition(context, i), mapper); + let contextualParameterType = getTypeAtPosition(context, i); + assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper); } if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) { let parameter = lastOrUndefined(signature.parameters); - let links = getSymbolLinks(parameter); - links.type = instantiateType(getTypeOfSymbol(lastOrUndefined(context.parameters)), mapper); + let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters)); + assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper); + } + } + + function assignTypeToParameterAndFixTypeParameters(parameterLinks: SymbolLinks, contextualType: Type, mapper: TypeMapper) { + if (!parameterLinks.type) { + parameterLinks.type = instantiateType(contextualType, mapper); + } + else if (isInferentialContext(mapper)) { + inferTypes(mapper.context, parameterLinks.type, contextualType, true); + fixTypeParametersAfterInferringFromContextualParameterTypes(mapper.context); } } @@ -9014,27 +9044,34 @@ namespace ts { let links = getNodeLinks(node); let type = getTypeOfSymbol(node.symbol); + let contextSensitive = isContextSensitive(node); + let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper); + // Check if function expression is contextually typed and assign parameter types if so - if (!(links.flags & NodeCheckFlags.ContextChecked)) { + if (mightFixTypeParameters || !(links.flags & NodeCheckFlags.ContextChecked)) { let contextualSignature = getContextualSignature(node); // If a type check is started at a function expression that is an argument of a function call, obtaining the // contextual type may recursively get back to here during overload resolution of the call. If so, we will have // already assigned contextual types. - if (!(links.flags & NodeCheckFlags.ContextChecked)) { + let contextChecked = !!(links.flags & NodeCheckFlags.ContextChecked); + if (mightFixTypeParameters || !contextChecked) { links.flags |= NodeCheckFlags.ContextChecked; if (contextualSignature) { let signature = getSignaturesOfType(type, SignatureKind.Call)[0]; - if (isContextSensitive(node)) { + if (contextSensitive) { assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper); } - if (!node.type && !signature.resolvedReturnType) { + if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) { let returnType = getReturnTypeFromBody(node, contextualMapper); if (!signature.resolvedReturnType) { signature.resolvedReturnType = returnType; } } } - checkSignatureDeclaration(node); + + if (!contextChecked) { + checkSignatureDeclaration(node); + } } } @@ -9724,7 +9761,7 @@ namespace ts { } function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) { - if (contextualMapper && contextualMapper !== identityMapper) { + if (isInferentialContext(contextualMapper)) { let signature = getSingleCallSignature(type); if (signature && signature.typeParameters) { let contextualType = getContextualType(node); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6c2f72a1ab..22dcc89b5e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1893,6 +1893,7 @@ namespace ts { /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; + context?: InferenceContext; } /* @internal */ @@ -1901,6 +1902,8 @@ namespace ts { 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 + + fixAfterInferringFromContextualParameterType: boolean; } /* @internal */ From f5ca4563252664ce0aedced5fd422f95f8e7173d Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 8 Jul 2015 14:49:54 -0700 Subject: [PATCH 2/7] Accept baselines --- .../parenthesizedContexualTyping1.types | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/baselines/reference/parenthesizedContexualTyping1.types b/tests/baselines/reference/parenthesizedContexualTyping1.types index b7307eaf3e..61ec1a24ec 100644 --- a/tests/baselines/reference/parenthesizedContexualTyping1.types +++ b/tests/baselines/reference/parenthesizedContexualTyping1.types @@ -146,8 +146,8 @@ var h = fun((((x => x))), ((x => x)), 10); // Ternaries in parens var i = fun((Math.random() < 0.5 ? x => x : x => undefined), 10); ->i : any ->fun((Math.random() < 0.5 ? x => x : x => undefined), 10) : any +>i : number +>fun((Math.random() < 0.5 ? x => x : x => undefined), 10) : number >fun : { (g: (x: T) => T, x: T): T; (g: (x: T) => T, h: (y: T) => T, x: T): T; } >(Math.random() < 0.5 ? x => x : x => undefined) : (x: number) => any >Math.random() < 0.5 ? x => x : x => undefined : (x: number) => any @@ -166,8 +166,8 @@ var i = fun((Math.random() < 0.5 ? x => x : x => undefined), 10); >10 : number var j = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10); ->j : any ->fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10) : any +>j : number +>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10) : number >fun : { (g: (x: T) => T, x: T): T; (g: (x: T) => T, h: (y: T) => T, x: T): T; } >(Math.random() < 0.5 ? (x => x) : (x => undefined)) : (x: number) => any >Math.random() < 0.5 ? (x => x) : (x => undefined) : (x: number) => any @@ -188,8 +188,8 @@ var j = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10); >10 : number var k = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10); ->k : any ->fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10) : any +>k : number +>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10) : number >fun : { (g: (x: T) => T, x: T): T; (g: (x: T) => T, h: (y: T) => T, x: T): T; } >(Math.random() < 0.5 ? (x => x) : (x => undefined)) : (x: number) => any >Math.random() < 0.5 ? (x => x) : (x => undefined) : (x: number) => any @@ -207,14 +207,14 @@ var k = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10); >x => undefined : (x: number) => any >x : number >undefined : undefined ->x => x : (x: any) => any ->x : any ->x : any +>x => x : (x: number) => number +>x : number +>x : number >10 : number var l = fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10); ->l : any ->fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10) : any +>l : number +>fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10) : number >fun : { (g: (x: T) => T, x: T): T; (g: (x: T) => T, h: (y: T) => T, x: T): T; } >((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))) : (x: number) => any >(Math.random() < 0.5 ? ((x => x)) : ((x => undefined))) : (x: number) => any @@ -235,11 +235,11 @@ var l = fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x) >x => undefined : (x: number) => any >x : number >undefined : undefined ->((x => x)) : (x: any) => any ->(x => x) : (x: any) => any ->x => x : (x: any) => any ->x : any ->x : any +>((x => x)) : (x: number) => number +>(x => x) : (x: number) => number +>x => x : (x: number) => number +>x : number +>x : number >10 : number var lambda1: (x: number) => number = x => x; From 263c54edd4713565c31f157cdc42b401f3abb2ca Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 8 Jul 2015 16:17:03 -0700 Subject: [PATCH 3/7] Add tests for type parameter fixing --- .../fixingTypeParametersRepeatedly1.js | 12 +++ .../fixingTypeParametersRepeatedly1.symbols | 51 ++++++++++++ .../fixingTypeParametersRepeatedly1.types | 63 +++++++++++++++ ...fixingTypeParametersRepeatedly2.errors.txt | 32 ++++++++ .../fixingTypeParametersRepeatedly2.js | 23 ++++++ .../fixingTypeParametersRepeatedly3.js | 23 ++++++ .../fixingTypeParametersRepeatedly3.symbols | 73 +++++++++++++++++ .../fixingTypeParametersRepeatedly3.types | 79 +++++++++++++++++++ .../fixingTypeParametersRepeatedly1.ts | 7 ++ .../fixingTypeParametersRepeatedly2.ts | 17 ++++ .../fixingTypeParametersRepeatedly3.ts | 17 ++++ .../fixingTypeParametersQuickInfo.ts | 13 +++ 12 files changed, 410 insertions(+) create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly1.js create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly1.symbols create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly1.types create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly2.errors.txt create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly2.js create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly3.js create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly3.symbols create mode 100644 tests/baselines/reference/fixingTypeParametersRepeatedly3.types create mode 100644 tests/cases/compiler/fixingTypeParametersRepeatedly1.ts create mode 100644 tests/cases/compiler/fixingTypeParametersRepeatedly2.ts create mode 100644 tests/cases/compiler/fixingTypeParametersRepeatedly3.ts create mode 100644 tests/cases/fourslash/fixingTypeParametersQuickInfo.ts diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly1.js b/tests/baselines/reference/fixingTypeParametersRepeatedly1.js new file mode 100644 index 0000000000..93ab8ba988 --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly1.js @@ -0,0 +1,12 @@ +//// [fixingTypeParametersRepeatedly1.ts] +declare function f(x: T, y: (p: T) => T, z: (p: T) => T): T; +f("", x => null, x => x.toLowerCase()); + +// First overload of g should type check just like f +declare function g(x: T, y: (p: T) => T, z: (p: T) => T): T; +declare function g(); +g("", x => null, x => x.toLowerCase()); + +//// [fixingTypeParametersRepeatedly1.js] +f("", function (x) { return null; }, function (x) { return x.toLowerCase(); }); +g("", function (x) { return null; }, function (x) { return x.toLowerCase(); }); diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly1.symbols b/tests/baselines/reference/fixingTypeParametersRepeatedly1.symbols new file mode 100644 index 0000000000..998e59c0b8 --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly1.symbols @@ -0,0 +1,51 @@ +=== tests/cases/compiler/fixingTypeParametersRepeatedly1.ts === +declare function f(x: T, y: (p: T) => T, z: (p: T) => T): T; +>f : Symbol(f, Decl(fixingTypeParametersRepeatedly1.ts, 0, 0)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 0, 22)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) +>y : Symbol(y, Decl(fixingTypeParametersRepeatedly1.ts, 0, 27)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 0, 32)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) +>z : Symbol(z, Decl(fixingTypeParametersRepeatedly1.ts, 0, 43)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 0, 48)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19)) + +f("", x => null, x => x.toLowerCase()); +>f : Symbol(f, Decl(fixingTypeParametersRepeatedly1.ts, 0, 0)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 1, 5)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 1, 16)) +>x.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 1, 16)) +>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51)) + +// First overload of g should type check just like f +declare function g(x: T, y: (p: T) => T, z: (p: T) => T): T; +>g : Symbol(g, Decl(fixingTypeParametersRepeatedly1.ts, 1, 39), Decl(fixingTypeParametersRepeatedly1.ts, 4, 63)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 4, 22)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) +>y : Symbol(y, Decl(fixingTypeParametersRepeatedly1.ts, 4, 27)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 4, 32)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) +>z : Symbol(z, Decl(fixingTypeParametersRepeatedly1.ts, 4, 43)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 4, 48)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19)) + +declare function g(); +>g : Symbol(g, Decl(fixingTypeParametersRepeatedly1.ts, 1, 39), Decl(fixingTypeParametersRepeatedly1.ts, 4, 63)) + +g("", x => null, x => x.toLowerCase()); +>g : Symbol(g, Decl(fixingTypeParametersRepeatedly1.ts, 1, 39), Decl(fixingTypeParametersRepeatedly1.ts, 4, 63)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 6, 5)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 6, 16)) +>x.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 6, 16)) +>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51)) + diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly1.types b/tests/baselines/reference/fixingTypeParametersRepeatedly1.types new file mode 100644 index 0000000000..273c66b342 --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly1.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/fixingTypeParametersRepeatedly1.ts === +declare function f(x: T, y: (p: T) => T, z: (p: T) => T): T; +>f : (x: T, y: (p: T) => T, z: (p: T) => T) => T +>T : T +>x : T +>T : T +>y : (p: T) => T +>p : T +>T : T +>T : T +>z : (p: T) => T +>p : T +>T : T +>T : T +>T : T + +f("", x => null, x => x.toLowerCase()); +>f("", x => null, x => x.toLowerCase()) : string +>f : (x: T, y: (p: T) => T, z: (p: T) => T) => T +>"" : string +>x => null : (x: string) => any +>x : string +>null : null +>x => x.toLowerCase() : (x: string) => string +>x : string +>x.toLowerCase() : string +>x.toLowerCase : () => string +>x : string +>toLowerCase : () => string + +// First overload of g should type check just like f +declare function g(x: T, y: (p: T) => T, z: (p: T) => T): T; +>g : { (x: T, y: (p: T) => T, z: (p: T) => T): T; (): any; } +>T : T +>x : T +>T : T +>y : (p: T) => T +>p : T +>T : T +>T : T +>z : (p: T) => T +>p : T +>T : T +>T : T +>T : T + +declare function g(); +>g : { (x: T, y: (p: T) => T, z: (p: T) => T): T; (): any; } + +g("", x => null, x => x.toLowerCase()); +>g("", x => null, x => x.toLowerCase()) : string +>g : { (x: T, y: (p: T) => T, z: (p: T) => T): T; (): any; } +>"" : string +>x => null : (x: string) => any +>x : string +>null : null +>x => x.toLowerCase() : (x: string) => string +>x : string +>x.toLowerCase() : string +>x.toLowerCase : () => string +>x : string +>toLowerCase : () => string + diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly2.errors.txt b/tests/baselines/reference/fixingTypeParametersRepeatedly2.errors.txt new file mode 100644 index 0000000000..e56b58a268 --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly2.errors.txt @@ -0,0 +1,32 @@ +tests/cases/compiler/fixingTypeParametersRepeatedly2.ts(11,27): error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'. + Type 'Base' is not assignable to type 'Derived'. + Property 'toBase' is missing in type 'Base'. +tests/cases/compiler/fixingTypeParametersRepeatedly2.ts(17,27): error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'. + Type 'Base' is not assignable to type 'Derived'. + + +==== tests/cases/compiler/fixingTypeParametersRepeatedly2.ts (2 errors) ==== + interface Base { + baseProp; + } + interface Derived extends Base { + toBase(): Base; + } + + var derived: Derived; + + declare function foo(x: T, func: (p: T) => T): T; + var result = foo(derived, d => d.toBase()); + ~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'. +!!! error TS2345: Type 'Base' is not assignable to type 'Derived'. +!!! error TS2345: Property 'toBase' is missing in type 'Base'. + + // bar should type check just like foo. + // The same error should be observed in both cases. + declare function bar(x: T, func: (p: T) => T): T; + declare function bar(x: T, func: (p: T) => T): T; + var result = bar(derived, d => d.toBase()); + ~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'. +!!! error TS2345: Type 'Base' is not assignable to type 'Derived'. \ No newline at end of file diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly2.js b/tests/baselines/reference/fixingTypeParametersRepeatedly2.js new file mode 100644 index 0000000000..9ebf426bbd --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly2.js @@ -0,0 +1,23 @@ +//// [fixingTypeParametersRepeatedly2.ts] +interface Base { + baseProp; +} +interface Derived extends Base { + toBase(): Base; +} + +var derived: Derived; + +declare function foo(x: T, func: (p: T) => T): T; +var result = foo(derived, d => d.toBase()); + +// bar should type check just like foo. +// The same error should be observed in both cases. +declare function bar(x: T, func: (p: T) => T): T; +declare function bar(x: T, func: (p: T) => T): T; +var result = bar(derived, d => d.toBase()); + +//// [fixingTypeParametersRepeatedly2.js] +var derived; +var result = foo(derived, function (d) { return d.toBase(); }); +var result = bar(derived, function (d) { return d.toBase(); }); diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly3.js b/tests/baselines/reference/fixingTypeParametersRepeatedly3.js new file mode 100644 index 0000000000..83a47c92c3 --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly3.js @@ -0,0 +1,23 @@ +//// [fixingTypeParametersRepeatedly3.ts] +interface Base { + baseProp; +} +interface Derived extends Base { + toBase?(): Base; +} + +var derived: Derived; + +declare function foo(x: T, func: (p: T) => T): T; +var result = foo(derived, d => d.toBase()); + +// bar should type check just like foo. +// result2 should have the same type as result +declare function bar(x: T, func: (p: T) => T): T; +declare function bar(x: T, func: (p: T) => T): T; +var result2 = bar(derived, d => d.toBase()); + +//// [fixingTypeParametersRepeatedly3.js] +var derived; +var result = foo(derived, function (d) { return d.toBase(); }); +var result2 = bar(derived, function (d) { return d.toBase(); }); diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly3.symbols b/tests/baselines/reference/fixingTypeParametersRepeatedly3.symbols new file mode 100644 index 0000000000..a849adb623 --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly3.symbols @@ -0,0 +1,73 @@ +=== tests/cases/compiler/fixingTypeParametersRepeatedly3.ts === +interface Base { +>Base : Symbol(Base, Decl(fixingTypeParametersRepeatedly3.ts, 0, 0)) + + baseProp; +>baseProp : Symbol(baseProp, Decl(fixingTypeParametersRepeatedly3.ts, 0, 16)) +} +interface Derived extends Base { +>Derived : Symbol(Derived, Decl(fixingTypeParametersRepeatedly3.ts, 2, 1)) +>Base : Symbol(Base, Decl(fixingTypeParametersRepeatedly3.ts, 0, 0)) + + toBase?(): Base; +>toBase : Symbol(toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32)) +>Base : Symbol(Base, Decl(fixingTypeParametersRepeatedly3.ts, 0, 0)) +} + +var derived: Derived; +>derived : Symbol(derived, Decl(fixingTypeParametersRepeatedly3.ts, 7, 3)) +>Derived : Symbol(Derived, Decl(fixingTypeParametersRepeatedly3.ts, 2, 1)) + +declare function foo(x: T, func: (p: T) => T): T; +>foo : Symbol(foo, Decl(fixingTypeParametersRepeatedly3.ts, 7, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly3.ts, 9, 24)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21)) +>func : Symbol(func, Decl(fixingTypeParametersRepeatedly3.ts, 9, 29)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly3.ts, 9, 37)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21)) + +var result = foo(derived, d => d.toBase()); +>result : Symbol(result, Decl(fixingTypeParametersRepeatedly3.ts, 10, 3)) +>foo : Symbol(foo, Decl(fixingTypeParametersRepeatedly3.ts, 7, 21)) +>derived : Symbol(derived, Decl(fixingTypeParametersRepeatedly3.ts, 7, 3)) +>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 10, 25)) +>d.toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32)) +>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 10, 25)) +>toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32)) + +// bar should type check just like foo. +// result2 should have the same type as result +declare function bar(x: T, func: (p: T) => T): T; +>bar : Symbol(bar, Decl(fixingTypeParametersRepeatedly3.ts, 10, 43), Decl(fixingTypeParametersRepeatedly3.ts, 14, 52)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly3.ts, 14, 24)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21)) +>func : Symbol(func, Decl(fixingTypeParametersRepeatedly3.ts, 14, 29)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly3.ts, 14, 37)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21)) + +declare function bar(x: T, func: (p: T) => T): T; +>bar : Symbol(bar, Decl(fixingTypeParametersRepeatedly3.ts, 10, 43), Decl(fixingTypeParametersRepeatedly3.ts, 14, 52)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21)) +>x : Symbol(x, Decl(fixingTypeParametersRepeatedly3.ts, 15, 24)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21)) +>func : Symbol(func, Decl(fixingTypeParametersRepeatedly3.ts, 15, 29)) +>p : Symbol(p, Decl(fixingTypeParametersRepeatedly3.ts, 15, 37)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21)) +>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21)) + +var result2 = bar(derived, d => d.toBase()); +>result2 : Symbol(result2, Decl(fixingTypeParametersRepeatedly3.ts, 16, 3)) +>bar : Symbol(bar, Decl(fixingTypeParametersRepeatedly3.ts, 10, 43), Decl(fixingTypeParametersRepeatedly3.ts, 14, 52)) +>derived : Symbol(derived, Decl(fixingTypeParametersRepeatedly3.ts, 7, 3)) +>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 16, 26)) +>d.toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32)) +>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 16, 26)) +>toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32)) + diff --git a/tests/baselines/reference/fixingTypeParametersRepeatedly3.types b/tests/baselines/reference/fixingTypeParametersRepeatedly3.types new file mode 100644 index 0000000000..3bf926276d --- /dev/null +++ b/tests/baselines/reference/fixingTypeParametersRepeatedly3.types @@ -0,0 +1,79 @@ +=== tests/cases/compiler/fixingTypeParametersRepeatedly3.ts === +interface Base { +>Base : Base + + baseProp; +>baseProp : any +} +interface Derived extends Base { +>Derived : Derived +>Base : Base + + toBase?(): Base; +>toBase : () => Base +>Base : Base +} + +var derived: Derived; +>derived : Derived +>Derived : Derived + +declare function foo(x: T, func: (p: T) => T): T; +>foo : (x: T, func: (p: T) => T) => T +>T : T +>x : T +>T : T +>func : (p: T) => T +>p : T +>T : T +>T : T +>T : T + +var result = foo(derived, d => d.toBase()); +>result : Derived +>foo(derived, d => d.toBase()) : Derived +>foo : (x: T, func: (p: T) => T) => T +>derived : Derived +>d => d.toBase() : (d: Derived) => Base +>d : Derived +>d.toBase() : Base +>d.toBase : () => Base +>d : Derived +>toBase : () => Base + +// bar should type check just like foo. +// result2 should have the same type as result +declare function bar(x: T, func: (p: T) => T): T; +>bar : { (x: T, func: (p: T) => T): T; (x: T, func: (p: T) => T): T; } +>T : T +>x : T +>T : T +>func : (p: T) => T +>p : T +>T : T +>T : T +>T : T + +declare function bar(x: T, func: (p: T) => T): T; +>bar : { (x: T, func: (p: T) => T): T; (x: T, func: (p: T) => T): T; } +>T : T +>x : T +>T : T +>func : (p: T) => T +>p : T +>T : T +>T : T +>T : T + +var result2 = bar(derived, d => d.toBase()); +>result2 : Derived +>bar(derived, d => d.toBase()) : Derived +>bar : { (x: T, func: (p: T) => T): T; (x: T, func: (p: T) => T): T; } +>derived : Derived +>d => d.toBase() : (d: Derived) => Base +>d : Derived +>d.toBase() : Base +>d.toBase : () => Base +>d : Derived +>toBase : () => Base + diff --git a/tests/cases/compiler/fixingTypeParametersRepeatedly1.ts b/tests/cases/compiler/fixingTypeParametersRepeatedly1.ts new file mode 100644 index 0000000000..d02e434c61 --- /dev/null +++ b/tests/cases/compiler/fixingTypeParametersRepeatedly1.ts @@ -0,0 +1,7 @@ +declare function f(x: T, y: (p: T) => T, z: (p: T) => T): T; +f("", x => null, x => x.toLowerCase()); + +// First overload of g should type check just like f +declare function g(x: T, y: (p: T) => T, z: (p: T) => T): T; +declare function g(); +g("", x => null, x => x.toLowerCase()); \ No newline at end of file diff --git a/tests/cases/compiler/fixingTypeParametersRepeatedly2.ts b/tests/cases/compiler/fixingTypeParametersRepeatedly2.ts new file mode 100644 index 0000000000..b439838862 --- /dev/null +++ b/tests/cases/compiler/fixingTypeParametersRepeatedly2.ts @@ -0,0 +1,17 @@ +interface Base { + baseProp; +} +interface Derived extends Base { + toBase(): Base; +} + +var derived: Derived; + +declare function foo(x: T, func: (p: T) => T): T; +var result = foo(derived, d => d.toBase()); + +// bar should type check just like foo. +// The same error should be observed in both cases. +declare function bar(x: T, func: (p: T) => T): T; +declare function bar(x: T, func: (p: T) => T): T; +var result = bar(derived, d => d.toBase()); \ No newline at end of file diff --git a/tests/cases/compiler/fixingTypeParametersRepeatedly3.ts b/tests/cases/compiler/fixingTypeParametersRepeatedly3.ts new file mode 100644 index 0000000000..1ffba2e50c --- /dev/null +++ b/tests/cases/compiler/fixingTypeParametersRepeatedly3.ts @@ -0,0 +1,17 @@ +interface Base { + baseProp; +} +interface Derived extends Base { + toBase?(): Base; +} + +var derived: Derived; + +declare function foo(x: T, func: (p: T) => T): T; +var result = foo(derived, d => d.toBase()); + +// bar should type check just like foo. +// result2 should have the same type as result +declare function bar(x: T, func: (p: T) => T): T; +declare function bar(x: T, func: (p: T) => T): T; +var result2 = bar(derived, d => d.toBase()); \ No newline at end of file diff --git a/tests/cases/fourslash/fixingTypeParametersQuickInfo.ts b/tests/cases/fourslash/fixingTypeParametersQuickInfo.ts new file mode 100644 index 0000000000..033663052b --- /dev/null +++ b/tests/cases/fourslash/fixingTypeParametersQuickInfo.ts @@ -0,0 +1,13 @@ +/// + +////declare function f(x: T, y: (p: T) => T, z: (p: T) => T): T; +////var /*1*/result = /*2*/f(0, /*3*/x => null, /*4*/x => x.blahblah); + +goTo.marker('1'); +verify.quickInfoIs('var result: number'); +goTo.marker('2'); +verify.quickInfoIs('function f(x: number, y: (p: number) => number, z: (p: number) => number): number'); +goTo.marker('3'); +verify.quickInfoIs('(parameter) x: number'); +goTo.marker('4'); +verify.quickInfoIs('(parameter) x: number'); \ No newline at end of file From d25bceaf8705d9ffc527332191c80d08d174500b Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 8 Jul 2015 16:37:18 -0700 Subject: [PATCH 4/7] Don't bother doing inference from the function parameter if you are about to fix the type parameter --- src/compiler/checker.ts | 28 ++++++---------------------- src/compiler/types.ts | 2 -- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 05174a4315..35d9abe2fb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4239,17 +4239,6 @@ namespace ts { return mapper; } - function fixTypeParametersAfterInferringFromContextualParameterTypes(context: InferenceContext): void { - for (let i = 0; i < context.typeParameters.length; i++) { - let typeParameterInfo = context.inferences[i]; - if (typeParameterInfo.fixAfterInferringFromContextualParameterType) { - typeParameterInfo.fixAfterInferringFromContextualParameterType = false; - typeParameterInfo.isFixed = true; - getInferredType(context, i); - } - } - } - function identityMapper(type: Type): Type { return type; } @@ -5412,8 +5401,7 @@ namespace ts { let inferences: TypeInferences[] = []; for (let unused of typeParameters) { inferences.push({ - primary: undefined, secondary: undefined, - isFixed: false, fixAfterInferringFromContextualParameterType: false + primary: undefined, secondary: undefined, isFixed: false }); } return { @@ -5424,7 +5412,7 @@ namespace ts { }; } - function inferTypes(context: InferenceContext, source: Type, target: Type, inferringFromContextuallyTypedParameter: boolean) { + function inferTypes(context: InferenceContext, source: Type, target: Type) { let sourceStack: Type[]; let targetStack: Type[]; let depth = 0; @@ -5463,9 +5451,6 @@ namespace ts { if (!contains(candidates, source)) { candidates.push(source); } - if (inferringFromContextuallyTypedParameter) { - inferences.fixAfterInferringFromContextualParameterType = true; - } } return; } @@ -7854,7 +7839,7 @@ namespace ts { let context = createInferenceContext(signature.typeParameters, /*inferUnionTypes*/ true); forEachMatchingParameterType(contextualSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type - inferTypes(context, instantiateType(source, contextualMapper), target, false); + inferTypes(context, instantiateType(source, contextualMapper), target); }); return getSignatureInstantiation(signature, getInferredTypes(context)); } @@ -7904,7 +7889,7 @@ namespace ts { argType = checkExpressionWithContextualType(arg, paramType, mapper); } - inferTypes(context, argType, paramType, false); + inferTypes(context, argType, paramType); } } @@ -7919,7 +7904,7 @@ namespace ts { if (excludeArgument[i] === false) { let arg = args[i]; let paramType = getTypeAtPosition(signature, i); - inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType, false); + inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); } } } @@ -8823,8 +8808,7 @@ namespace ts { parameterLinks.type = instantiateType(contextualType, mapper); } else if (isInferentialContext(mapper)) { - inferTypes(mapper.context, parameterLinks.type, contextualType, true); - fixTypeParametersAfterInferringFromContextualParameterTypes(mapper.context); + inferTypes(mapper.context, parameterLinks.type, instantiateType(contextualType, mapper)); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 22dcc89b5e..7c893da9a6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1902,8 +1902,6 @@ namespace ts { 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 - - fixAfterInferringFromContextualParameterType: boolean; } /* @internal */ From a660d7bbea42d51a263058c2f5f5ef83dd3696ea Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 8 Jul 2015 17:15:05 -0700 Subject: [PATCH 5/7] Add hopefully helpful comments --- src/compiler/checker.ts | 46 ++++++++++++++++++++++++++++++++++------- src/compiler/types.ts | 4 +++- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 35d9abe2fb..534deb5fde 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8794,21 +8794,51 @@ namespace ts { for (let i = 0; i < len; i++) { let parameter = signature.parameters[i]; let contextualParameterType = getTypeAtPosition(context, i); - assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper); + assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper); } if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) { let parameter = lastOrUndefined(signature.parameters); let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters)); - assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper); + assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper); } } - function assignTypeToParameterAndFixTypeParameters(parameterLinks: SymbolLinks, contextualType: Type, mapper: TypeMapper) { - if (!parameterLinks.type) { - parameterLinks.type = instantiateType(contextualType, mapper); + function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper) { + let links = getSymbolLinks(parameter); + if (!links.type) { + links.type = instantiateType(contextualType, mapper); } else if (isInferentialContext(mapper)) { - inferTypes(mapper.context, parameterLinks.type, instantiateType(contextualType, mapper)); + // Even if the parameter already has a type, it might be because it was given a type while + // processing the function as an argument to a prior signature during overload resolution. + // If this was the case, it may have caused some type parameters to be fixed. So here, + // we need to ensure that type parameters at the same positions get fixed again. This is + // done by calling instantiateType to attach the mapper to the contextualType, and then + // calling inferTypes to force a walk of contextualType so that all the correct fixing + // happens. The choice to pass in links.type may seem kind of arbitrary, but it serves + // to make sure that all the correct positions in contextualType are reached by the walk. + // Here is an example: + // + // interface Base { + // baseProp; + // } + // interface Derived extends Base { + // toBase(): Base; + // } + // + // var derived: Derived; + // + // declare function foo(x: T, func: (p: T) => T): T; + // declare function foo(x: T, func: (p: T) => T): T; + // + // var result = foo(derived, d => d.toBase()); + // + // We are typing d while checking the second overload. But we've already given d + // a type (Derived) from the first overload. However, we still want to fix the + // T in the second overload so that we do not infer Base as a candidate for T + // (inferring Base would make type argument inference inconsistent between the two + // overloads). + inferTypes(mapper.context, links.type, instantiateType(contextualType, mapper)); } } @@ -9031,7 +9061,9 @@ namespace ts { let contextSensitive = isContextSensitive(node); let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper); - // Check if function expression is contextually typed and assign parameter types if so + // Check if function expression is contextually typed and assign parameter types if so. + // See the comment in assignTypeToParameterAndFixTypeParameters to understand why we need to + // check mightFixTypeParameters. if (mightFixTypeParameters || !(links.flags & NodeCheckFlags.ContextChecked)) { let contextualSignature = getContextualSignature(node); // If a type check is started at a function expression that is an argument of a function call, obtaining the diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7c893da9a6..4b19ece77c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1893,7 +1893,9 @@ namespace ts { /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; - context?: InferenceContext; + context?: InferenceContext; // The inference context this mapper was created from. + // Only inference mappers have this set (in createInferenceMapper). + // The identity mapper and regular instantiation mappers do not need it. } /* @internal */ From dcbb2e5f0f728b5788a255a7ba56b45816c0a75f Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Fri, 10 Jul 2015 11:35:03 -0700 Subject: [PATCH 6/7] Add a comment for isInferentialContext --- src/compiler/checker.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 534deb5fde..19c7c094c2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6700,8 +6700,21 @@ namespace ts { return result; } - // Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is - // used as a special marker for other purposes. + /** + * Detect if the mapper implies an inference context. Specifically, there are 4 possible values + * for a mapper. Let's go through each one of them: + * + * 1. undefined - this means we are not doing inferential typing, but we may do contextual typing, + * which could cause us to assign a parameter type + * 2. identityMapper - means we want to avoid assigning a parameter type, whether or not we are in + * inferential typing (context is undefined for the identityMapper) + * 3. a mapper created by createInferenceMapper - we are doing inferential typing, we want to assign + * parameter types and fix type parameters (context is defined) + * 4. an instantiation mapper created by createTypeMapper or createTypeEraser - this should never be + * passed as the contextual mapper when checking an expression (context is undefined for these) + * + * isInferentialContext is detecting if we are in case 3 + */ function isInferentialContext(mapper: TypeMapper) { return mapper && mapper.context; } From 6df0f3d4aa5fe90aee4a6fe64b2a55d814083dba Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Fri, 17 Jul 2015 14:52:24 -0700 Subject: [PATCH 7/7] Fix comment --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0fcc1a0ada..86f4629729 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6783,11 +6783,11 @@ namespace ts { * for a mapper. Let's go through each one of them: * * 1. undefined - this means we are not doing inferential typing, but we may do contextual typing, - * which could cause us to assign a parameter type - * 2. identityMapper - means we want to avoid assigning a parameter type, whether or not we are in + * which could cause us to assign a parameter a type + * 2. identityMapper - means we want to avoid assigning a parameter a type, whether or not we are in * inferential typing (context is undefined for the identityMapper) * 3. a mapper created by createInferenceMapper - we are doing inferential typing, we want to assign - * parameter types and fix type parameters (context is defined) + * types to parameters and fix type parameters (context is defined) * 4. an instantiation mapper created by createTypeMapper or createTypeEraser - this should never be * passed as the contextual mapper when checking an expression (context is undefined for these) *