Assign and instantiate contextual this type if not present

This commit is contained in:
Nathan Shively-Sanders 2016-08-17 14:21:49 -07:00
parent 271ffc84a5
commit 0f483d6546
9 changed files with 72 additions and 67 deletions

View File

@ -4785,9 +4785,6 @@ namespace ts {
function getThisTypeOfSignature(signature: Signature): Type | undefined {
if (signature.thisParameter) {
if (signature.mapper) {
signature = instantiateSignature(signature, signature.mapper);
}
return getTypeOfSymbol(signature.thisParameter);
}
}
@ -9085,15 +9082,15 @@ namespace ts {
return getInferredClassType(classSymbol);
}
}
const type = getContextuallyTypedThisType(container);
if (type) {
return type;
}
const thisType = getThisTypeOfDeclaration(container);
if (thisType) {
return thisType;
}
const type = getContextuallyTypedThisType(container);
if (type) {
return type;
}
}
if (isClassLike(container.parent)) {
const symbol = getSymbolOfNode(container.parent);
@ -12277,8 +12274,10 @@ namespace ts {
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
if (context.thisParameter) {
// save the mapper in case we need to type `this` later
context.mapper = mapper;
if (!signature.thisParameter) {
signature.thisParameter = createTransientSymbol(context.thisParameter, undefined);
}
assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper);
}
for (let i = 0; i < len; i++) {
const parameter = signature.parameters[i];

View File

@ -2,7 +2,7 @@
interface JQuery {
each<T>(
collection: T[], callback: (this: T, dit: T) => T
): any;
): T[];
}
let $: JQuery;

View File

@ -16,7 +16,8 @@ interface JQuery {
>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9))
>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9))
): any;
): T[];
>T : Symbol(T, Decl(instantiateContextuallyTypedGenericThis.ts, 1, 9))
}
let $: JQuery;
@ -38,6 +39,7 @@ $.each(lines, function(dit) {
>dit : Symbol(dit, Decl(instantiateContextuallyTypedGenericThis.ts, 8, 23))
>charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --))
>this.charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --))
>this : Symbol(this, Decl(instantiateContextuallyTypedGenericThis.ts, 2, 36))
>charAt : Symbol(String.charAt, Decl(lib.d.ts, --, --))
});

View File

@ -3,7 +3,7 @@ interface JQuery {
>JQuery : JQuery
each<T>(
>each : <T>(collection: T[], callback: (this: T, dit: T) => T) => any
>each : <T>(collection: T[], callback: (this: T, dit: T) => T) => T[]
>T : T
collection: T[], callback: (this: T, dit: T) => T
@ -16,7 +16,8 @@ interface JQuery {
>T : T
>T : T
): any;
): T[];
>T : T
}
let $: JQuery;
@ -27,12 +28,12 @@ let lines: string[];
>lines : string[]
$.each(lines, function(dit) {
>$.each(lines, function(dit) { return dit.charAt(0) + this.charAt(1);}) : any
>$.each : <T>(collection: T[], callback: (this: T, dit: T) => T) => any
>$.each(lines, function(dit) { return dit.charAt(0) + this.charAt(1);}) : string[]
>$.each : <T>(collection: T[], callback: (this: T, dit: T) => T) => T[]
>$ : JQuery
>each : <T>(collection: T[], callback: (this: T, dit: T) => T) => any
>each : <T>(collection: T[], callback: (this: T, dit: T) => T) => T[]
>lines : string[]
>function(dit) { return dit.charAt(0) + this.charAt(1);} : (dit: string) => string
>function(dit) { return dit.charAt(0) + this.charAt(1);} : (this: string, dit: string) => string
>dit : string
return dit.charAt(0) + this.charAt(1);

View File

@ -135,7 +135,7 @@ let impl: I = {
return this.a;
>this.a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30))
>this : Symbol(, Decl(thisTypeInFunctions.ts, 24, 28))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 24, 23))
>a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30))
},
@ -144,7 +144,7 @@ let impl: I = {
return this.a;
>this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
>this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 25, 22))
>a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
},
@ -153,7 +153,7 @@ let impl: I = {
return this.a;
>this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
>this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 26, 17))
>a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
},
@ -173,7 +173,7 @@ impl.explicitStructural = function() { return this.a; };
>impl : Symbol(impl, Decl(thisTypeInFunctions.ts, 37, 3))
>explicitStructural : Symbol(I.explicitStructural, Decl(thisTypeInFunctions.ts, 23, 38))
>this.a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30))
>this : Symbol(, Decl(thisTypeInFunctions.ts, 24, 28))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 24, 23))
>a : Symbol(a, Decl(thisTypeInFunctions.ts, 24, 30))
impl.explicitInterface = function() { return this.a; };
@ -181,7 +181,7 @@ impl.explicitInterface = function() { return this.a; };
>impl : Symbol(impl, Decl(thisTypeInFunctions.ts, 37, 3))
>explicitInterface : Symbol(I.explicitInterface, Decl(thisTypeInFunctions.ts, 24, 50))
>this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
>this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 25, 22))
>a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
impl.explicitStructural = () => 12;
@ -199,7 +199,7 @@ impl.explicitThis = function () { return this.a; };
>impl : Symbol(impl, Decl(thisTypeInFunctions.ts, 37, 3))
>explicitThis : Symbol(I.explicitThis, Decl(thisTypeInFunctions.ts, 25, 39))
>this.a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
>this : Symbol(I, Decl(thisTypeInFunctions.ts, 19, 21))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 26, 17))
>a : Symbol(I.a, Decl(thisTypeInFunctions.ts, 20, 13))
// parameter checking
@ -536,7 +536,7 @@ c.explicitC = function(m) { return this.n + m };
>explicitC : Symbol(C.explicitC, Decl(thisTypeInFunctions.ts, 8, 5))
>m : Symbol(m, Decl(thisTypeInFunctions.ts, 126, 23))
>this.n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9))
>this : Symbol(C, Decl(thisTypeInFunctions.ts, 3, 1))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 9, 14))
>n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9))
>m : Symbol(m, Decl(thisTypeInFunctions.ts, 126, 23))
@ -546,7 +546,7 @@ c.explicitProperty = function(m) { return this.n + m };
>explicitProperty : Symbol(C.explicitProperty, Decl(thisTypeInFunctions.ts, 11, 5))
>m : Symbol(m, Decl(thisTypeInFunctions.ts, 127, 30))
>this.n : Symbol(n, Decl(thisTypeInFunctions.ts, 12, 28))
>this : Symbol(, Decl(thisTypeInFunctions.ts, 12, 26))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 12, 21))
>n : Symbol(n, Decl(thisTypeInFunctions.ts, 12, 28))
>m : Symbol(m, Decl(thisTypeInFunctions.ts, 127, 30))
@ -556,7 +556,7 @@ c.explicitThis = function(m) { return this.n + m };
>explicitThis : Symbol(C.explicitThis, Decl(thisTypeInFunctions.ts, 5, 14))
>m : Symbol(m, Decl(thisTypeInFunctions.ts, 128, 26))
>this.n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9))
>this : Symbol(C, Decl(thisTypeInFunctions.ts, 3, 1))
>this : Symbol(this, Decl(thisTypeInFunctions.ts, 6, 17))
>n : Symbol(C.n, Decl(thisTypeInFunctions.ts, 4, 9))
>m : Symbol(m, Decl(thisTypeInFunctions.ts, 128, 26))

View File

@ -132,7 +132,7 @@ function implicitThis(n: number): number {
let impl: I = {
>impl : I
>I : I
>{ a: 12, explicitVoid2: () => this.a, // ok, this: any because it refers to some outer object (window?) explicitVoid1() { return 12; }, explicitStructural() { return this.a; }, explicitInterface() { return this.a; }, explicitThis() { return this.a; },} : { a: number; explicitVoid2: () => any; explicitVoid1(): number; explicitStructural(): number; explicitInterface(): number; explicitThis(): number; }
>{ a: 12, explicitVoid2: () => this.a, // ok, this: any because it refers to some outer object (window?) explicitVoid1() { return 12; }, explicitStructural() { return this.a; }, explicitInterface() { return this.a; }, explicitThis() { return this.a; },} : { a: number; explicitVoid2: () => any; explicitVoid1(this: void): number; explicitStructural(this: { a: number; }): number; explicitInterface(this: I): number; explicitThis(this: I): number; }
a: 12,
>a : number
@ -146,11 +146,11 @@ let impl: I = {
>a : any
explicitVoid1() { return 12; },
>explicitVoid1 : () => number
>explicitVoid1 : (this: void) => number
>12 : number
explicitStructural() {
>explicitStructural : () => number
>explicitStructural : (this: { a: number; }) => number
return this.a;
>this.a : number
@ -159,7 +159,7 @@ let impl: I = {
},
explicitInterface() {
>explicitInterface : () => number
>explicitInterface : (this: I) => number
return this.a;
>this.a : number
@ -168,7 +168,7 @@ let impl: I = {
},
explicitThis() {
>explicitThis : () => number
>explicitThis : (this: I) => number
return this.a;
>this.a : number
@ -178,11 +178,11 @@ let impl: I = {
},
}
impl.explicitVoid1 = function () { return 12; };
>impl.explicitVoid1 = function () { return 12; } : () => number
>impl.explicitVoid1 = function () { return 12; } : (this: void) => number
>impl.explicitVoid1 : (this: void) => number
>impl : I
>explicitVoid1 : (this: void) => number
>function () { return 12; } : () => number
>function () { return 12; } : (this: void) => number
>12 : number
impl.explicitVoid2 = () => 12;
@ -194,21 +194,21 @@ impl.explicitVoid2 = () => 12;
>12 : number
impl.explicitStructural = function() { return this.a; };
>impl.explicitStructural = function() { return this.a; } : () => number
>impl.explicitStructural = function() { return this.a; } : (this: { a: number; }) => number
>impl.explicitStructural : (this: { a: number; }) => number
>impl : I
>explicitStructural : (this: { a: number; }) => number
>function() { return this.a; } : () => number
>function() { return this.a; } : (this: { a: number; }) => number
>this.a : number
>this : { a: number; }
>a : number
impl.explicitInterface = function() { return this.a; };
>impl.explicitInterface = function() { return this.a; } : () => number
>impl.explicitInterface = function() { return this.a; } : (this: I) => number
>impl.explicitInterface : (this: I) => number
>impl : I
>explicitInterface : (this: I) => number
>function() { return this.a; } : () => number
>function() { return this.a; } : (this: I) => number
>this.a : number
>this : I
>a : number
@ -230,11 +230,11 @@ impl.explicitInterface = () => 12;
>12 : number
impl.explicitThis = function () { return this.a; };
>impl.explicitThis = function () { return this.a; } : () => number
>impl.explicitThis = function () { return this.a; } : (this: I) => number
>impl.explicitThis : (this: I) => number
>impl : I
>explicitThis : (this: I) => number
>function () { return this.a; } : () => number
>function () { return this.a; } : (this: I) => number
>this.a : number
>this : I
>a : number
@ -433,7 +433,7 @@ let unboundToSpecified: (this: { y: number }, x: number) => number = x => x + th
>this : { y: number; }
>y : number
>x : number
>x => x + this.y : (x: number) => any
>x => x + this.y : (this: { y: number; }, x: number) => any
>x : number
>x + this.y : any
>x : number
@ -472,7 +472,7 @@ let specifiedLambda: (this: void, x: number) => number = x => x + 12;
>specifiedLambda : (this: void, x: number) => number
>this : void
>x : number
>x => x + 12 : (x: number) => number
>x => x + 12 : (this: void, x: number) => number
>x : number
>x + 12 : number
>x : number
@ -560,40 +560,40 @@ c.explicitProperty = reconstructed.explicitProperty;
// lambdas are assignable to anything
c.explicitC = m => m;
>c.explicitC = m => m : (m: number) => number
>c.explicitC = m => m : (this: C, m: number) => number
>c.explicitC : (this: C, m: number) => number
>c : C
>explicitC : (this: C, m: number) => number
>m => m : (m: number) => number
>m => m : (this: C, m: number) => number
>m : number
>m : number
c.explicitThis = m => m;
>c.explicitThis = m => m : (m: number) => number
>c.explicitThis = m => m : (this: C, m: number) => number
>c.explicitThis : (this: C, m: number) => number
>c : C
>explicitThis : (this: C, m: number) => number
>m => m : (m: number) => number
>m => m : (this: C, m: number) => number
>m : number
>m : number
c.explicitProperty = m => m;
>c.explicitProperty = m => m : (m: number) => number
>c.explicitProperty = m => m : (this: { n: number; }, m: number) => number
>c.explicitProperty : (this: { n: number; }, m: number) => number
>c : C
>explicitProperty : (this: { n: number; }, m: number) => number
>m => m : (m: number) => number
>m => m : (this: { n: number; }, m: number) => number
>m : number
>m : number
// this inside lambdas refer to outer scope
// the outer-scoped lambda at top-level is still just `any`
c.explicitC = m => m + this.n;
>c.explicitC = m => m + this.n : (m: number) => any
>c.explicitC = m => m + this.n : (this: C, m: number) => any
>c.explicitC : (this: C, m: number) => number
>c : C
>explicitC : (this: C, m: number) => number
>m => m + this.n : (m: number) => any
>m => m + this.n : (this: C, m: number) => any
>m : number
>m + this.n : any
>m : number
@ -602,11 +602,11 @@ c.explicitC = m => m + this.n;
>n : any
c.explicitThis = m => m + this.n;
>c.explicitThis = m => m + this.n : (m: number) => any
>c.explicitThis = m => m + this.n : (this: C, m: number) => any
>c.explicitThis : (this: C, m: number) => number
>c : C
>explicitThis : (this: C, m: number) => number
>m => m + this.n : (m: number) => any
>m => m + this.n : (this: C, m: number) => any
>m : number
>m + this.n : any
>m : number
@ -615,11 +615,11 @@ c.explicitThis = m => m + this.n;
>n : any
c.explicitProperty = m => m + this.n;
>c.explicitProperty = m => m + this.n : (m: number) => any
>c.explicitProperty = m => m + this.n : (this: { n: number; }, m: number) => any
>c.explicitProperty : (this: { n: number; }, m: number) => number
>c : C
>explicitProperty : (this: { n: number; }, m: number) => number
>m => m + this.n : (m: number) => any
>m => m + this.n : (this: { n: number; }, m: number) => any
>m : number
>m + this.n : any
>m : number
@ -652,11 +652,11 @@ c.explicitThis = function(this: C, m: number) { return this.n + m };
// this:any compatibility
c.explicitC = function(m) { return this.n + m };
>c.explicitC = function(m) { return this.n + m } : (m: number) => number
>c.explicitC = function(m) { return this.n + m } : (this: C, m: number) => number
>c.explicitC : (this: C, m: number) => number
>c : C
>explicitC : (this: C, m: number) => number
>function(m) { return this.n + m } : (m: number) => number
>function(m) { return this.n + m } : (this: C, m: number) => number
>m : number
>this.n + m : number
>this.n : number
@ -665,11 +665,11 @@ c.explicitC = function(m) { return this.n + m };
>m : number
c.explicitProperty = function(m) { return this.n + m };
>c.explicitProperty = function(m) { return this.n + m } : (m: number) => number
>c.explicitProperty = function(m) { return this.n + m } : (this: { n: number; }, m: number) => number
>c.explicitProperty : (this: { n: number; }, m: number) => number
>c : C
>explicitProperty : (this: { n: number; }, m: number) => number
>function(m) { return this.n + m } : (m: number) => number
>function(m) { return this.n + m } : (this: { n: number; }, m: number) => number
>m : number
>this.n + m : number
>this.n : number
@ -678,11 +678,11 @@ c.explicitProperty = function(m) { return this.n + m };
>m : number
c.explicitThis = function(m) { return this.n + m };
>c.explicitThis = function(m) { return this.n + m } : (m: number) => number
>c.explicitThis = function(m) { return this.n + m } : (this: C, m: number) => number
>c.explicitThis : (this: C, m: number) => number
>c : C
>explicitThis : (this: C, m: number) => number
>function(m) { return this.n + m } : (m: number) => number
>function(m) { return this.n + m } : (this: C, m: number) => number
>m : number
>this.n + m : number
>this.n : number
@ -723,11 +723,11 @@ c.explicitC = function(this: B, m: number) { return this.n + m };
// this:void compatibility
c.explicitVoid = n => n;
>c.explicitVoid = n => n : (n: number) => number
>c.explicitVoid = n => n : (this: void, n: number) => number
>c.explicitVoid : (this: void, m: number) => number
>c : C
>explicitVoid : (this: void, m: number) => number
>n => n : (n: number) => number
>n => n : (this: void, n: number) => number
>n : number
>n : number

View File

@ -61,12 +61,12 @@ extend1({
>init : Symbol(init, Decl(thisTypeInFunctions2.ts, 20, 9))
this // this: IndexedWithThis because of contextual typing.
>this : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0))
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 2, 12))
// this.mine
this.willDestroy
>this.willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32))
>this : Symbol(IndexedWithThis, Decl(thisTypeInFunctions2.ts, 0, 0))
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 2, 12))
>willDestroy : Symbol(IndexedWithThis.willDestroy, Decl(thisTypeInFunctions2.ts, 2, 32))
},
@ -77,7 +77,10 @@ extend1({
>foo : Symbol(foo, Decl(thisTypeInFunctions2.ts, 26, 13))
this.url; // this: any because 'foo' matches the string indexer
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 4, 87))
this.willDestroy;
>this : Symbol(this, Decl(thisTypeInFunctions2.ts, 4, 87))
}
});
extend2({

View File

@ -58,10 +58,10 @@ declare function simple(arg: SimpleInterface): void;
extend1({
>extend1({ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }}) : void
>extend1 : (args: IndexedWithThis) => void
>{ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }} : { init(): void; mine: number; foo(): void; }
>{ init() { this // this: IndexedWithThis because of contextual typing. // this.mine this.willDestroy }, mine: 12, foo() { this.url; // this: any because 'foo' matches the string indexer this.willDestroy; }} : { init(this: IndexedWithThis): void; mine: number; foo(this: any): void; }
init() {
>init : () => void
>init : (this: IndexedWithThis) => void
this // this: IndexedWithThis because of contextual typing.
>this : IndexedWithThis
@ -78,7 +78,7 @@ extend1({
>12 : number
foo() {
>foo : () => void
>foo : (this: any) => void
this.url; // this: any because 'foo' matches the string indexer
>this.url : any

View File

@ -1,7 +1,7 @@
interface JQuery {
each<T>(
collection: T[], callback: (this: T, dit: T) => T
): any;
): T[];
}
let $: JQuery;