Merge pull request #3724 from Microsoft/apparentTypeOfContextualType

Always get the apparent type when retrieving a contextual type
This commit is contained in:
Jason Freeman 2015-07-06 10:18:21 -07:00
commit f126767eb3
21 changed files with 391 additions and 36 deletions

View File

@ -6442,6 +6442,11 @@ namespace ts {
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
// be "pushed" onto a node using the contextualType property.
function getContextualType(node: Expression): Type {
let type = getContextualTypeWorker(node);
return type && getApparentType(type);
}
function getContextualTypeWorker(node: Expression): Type {
if (isInsideWithStatementBody(node)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return undefined;

View File

@ -98,7 +98,7 @@ x2 += E.a;
x2 += {};
>x2 += {} : string
>x2 : string
>{} : {}
>{} : { [x: number]: undefined; }
x2 += null;
>x2 += null : string

View File

@ -82,5 +82,7 @@ var x4: IWithCallSignatures | IWithCallSignatures4 = a => /*here a should be any
>IWithCallSignatures : Symbol(IWithCallSignatures, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 9, 1))
>IWithCallSignatures4 : Symbol(IWithCallSignatures4, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 18, 1))
>a : Symbol(a, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 35, 52))
>a.toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
>a : Symbol(a, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 35, 52))
>toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))

View File

@ -90,10 +90,10 @@ var x4: IWithCallSignatures | IWithCallSignatures4 = a => /*here a should be any
>x4 : IWithCallSignatures | IWithCallSignatures4
>IWithCallSignatures : IWithCallSignatures
>IWithCallSignatures4 : IWithCallSignatures4
>a => /*here a should be any*/ a.toString() : (a: any) => any
>a : any
>a.toString() : any
>a.toString : any
>a : any
>toString : any
>a => /*here a should be any*/ a.toString() : (a: number) => string
>a : number
>a.toString() : string
>a.toString : (radix?: number) => string
>a : number
>toString : (radix?: number) => string

View File

@ -37,12 +37,12 @@ var c: { (): string; (x): string };
>x : any
var r1 = foo((x) => x);
>r1 : (x: any) => any
>foo((x) => x) : (x: any) => any
>r1 : (x: string) => string
>foo((x) => x) : (x: string) => string
>foo : <T extends (x: string) => string>(x: T) => T
>(x) => x : (x: any) => any
>x : any
>x : any
>(x) => x : (x: string) => string
>x : string
>x : string
var r2 = foo((x: string) => x);
>r2 : (x: string) => string
@ -53,12 +53,12 @@ var r2 = foo((x: string) => x);
>x : string
var r3 = foo(function (x) { return x });
>r3 : (x: any) => any
>foo(function (x) { return x }) : (x: any) => any
>r3 : (x: string) => string
>foo(function (x) { return x }) : (x: string) => string
>foo : <T extends (x: string) => string>(x: T) => T
>function (x) { return x } : (x: any) => any
>x : any
>x : any
>function (x) { return x } : (x: string) => string
>x : string
>x : string
var r4 = foo(function (x: string) { return x });
>r4 : (x: string) => string
@ -130,8 +130,8 @@ var c2: { <T>(x: T): T; <T>(x: T, y: T): T };
>T : T
var r9 = foo(function <U>(x: U) { return x; });
>r9 : <U>(x: U) => U
>foo(function <U>(x: U) { return x; }) : <U>(x: U) => U
>r9 : (x: string) => string
>foo(function <U>(x: U) { return x; }) : (x: string) => string
>foo : <T extends (x: string) => string>(x: T) => T
>function <U>(x: U) { return x; } : <U>(x: U) => U
>U : U
@ -140,8 +140,8 @@ var r9 = foo(function <U>(x: U) { return x; });
>x : U
var r10 = foo(<U extends string>(x: U) => x);
>r10 : <U extends string>(x: U) => U
>foo(<U extends string>(x: U) => x) : <U extends string>(x: U) => U
>r10 : (x: string) => string
>foo(<U extends string>(x: U) => x) : (x: string) => string
>foo : <T extends (x: string) => string>(x: T) => T
><U extends string>(x: U) => x : <U extends string>(x: U) => U
>U : U

View File

@ -9,9 +9,9 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(22,1): error TS2322: Type '[number, string]' is not assignable to type '[string, number]'.
Types of property '0' are incompatible.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(23,1): error TS2322: Type '[{}, {}]' is not assignable to type '[string, number]'.
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(23,1): error TS2322: Type '[{ [x: number]: undefined; }, {}]' is not assignable to type '[string, number]'.
Types of property '0' are incompatible.
Type '{}' is not assignable to type 'string'.
Type '{ [x: number]: undefined; }' is not assignable to type 'string'.
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(24,1): error TS2322: Type '[{}]' is not assignable to type '[{}, {}]'.
Property '1' is missing in type '[{}]'.
@ -55,9 +55,9 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup
!!! error TS2322: Type 'number' is not assignable to type 'string'.
i1.tuple1 = [{}, {}];
~~~~~~~~~
!!! error TS2322: Type '[{}, {}]' is not assignable to type '[string, number]'.
!!! error TS2322: Type '[{ [x: number]: undefined; }, {}]' is not assignable to type '[string, number]'.
!!! error TS2322: Types of property '0' are incompatible.
!!! error TS2322: Type '{}' is not assignable to type 'string'.
!!! error TS2322: Type '{ [x: number]: undefined; }' is not assignable to type 'string'.
i2.tuple1 = [{}];
~~~~~~~~~
!!! error TS2322: Type '[{}]' is not assignable to type '[{}, {}]'.

View File

@ -0,0 +1,12 @@
//// [inferentialTypingUsingApparentType1.ts]
function foo<T extends (p: string) => number>(x: T): T {
return undefined;
}
foo(x => x.length);
//// [inferentialTypingUsingApparentType1.js]
function foo(x) {
return undefined;
}
foo(function (x) { return x.length; });

View File

@ -0,0 +1,20 @@
=== tests/cases/compiler/inferentialTypingUsingApparentType1.ts ===
function foo<T extends (p: string) => number>(x: T): T {
>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType1.ts, 0, 0))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType1.ts, 0, 13))
>p : Symbol(p, Decl(inferentialTypingUsingApparentType1.ts, 0, 24))
>x : Symbol(x, Decl(inferentialTypingUsingApparentType1.ts, 0, 46))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType1.ts, 0, 13))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType1.ts, 0, 13))
return undefined;
>undefined : Symbol(undefined)
}
foo(x => x.length);
>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType1.ts, 0, 0))
>x : Symbol(x, Decl(inferentialTypingUsingApparentType1.ts, 4, 4))
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(inferentialTypingUsingApparentType1.ts, 4, 4))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))

View File

@ -0,0 +1,22 @@
=== tests/cases/compiler/inferentialTypingUsingApparentType1.ts ===
function foo<T extends (p: string) => number>(x: T): T {
>foo : <T extends (p: string) => number>(x: T) => T
>T : T
>p : string
>x : T
>T : T
>T : T
return undefined;
>undefined : undefined
}
foo(x => x.length);
>foo(x => x.length) : (x: string) => number
>foo : <T extends (p: string) => number>(x: T) => T
>x => x.length : (x: string) => number
>x : string
>x.length : number
>x : string
>length : number

View File

@ -0,0 +1,12 @@
//// [inferentialTypingUsingApparentType2.ts]
function foo<T extends { m(p: string): number }>(x: T): T {
return undefined;
}
foo({ m(x) { return x.length } });
//// [inferentialTypingUsingApparentType2.js]
function foo(x) {
return undefined;
}
foo({ m: function (x) { return x.length; } });

View File

@ -0,0 +1,22 @@
=== tests/cases/compiler/inferentialTypingUsingApparentType2.ts ===
function foo<T extends { m(p: string): number }>(x: T): T {
>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType2.ts, 0, 0))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType2.ts, 0, 13))
>m : Symbol(m, Decl(inferentialTypingUsingApparentType2.ts, 0, 24))
>p : Symbol(p, Decl(inferentialTypingUsingApparentType2.ts, 0, 27))
>x : Symbol(x, Decl(inferentialTypingUsingApparentType2.ts, 0, 49))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType2.ts, 0, 13))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType2.ts, 0, 13))
return undefined;
>undefined : Symbol(undefined)
}
foo({ m(x) { return x.length } });
>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType2.ts, 0, 0))
>m : Symbol(m, Decl(inferentialTypingUsingApparentType2.ts, 4, 5))
>x : Symbol(x, Decl(inferentialTypingUsingApparentType2.ts, 4, 8))
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(inferentialTypingUsingApparentType2.ts, 4, 8))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))

View File

@ -0,0 +1,24 @@
=== tests/cases/compiler/inferentialTypingUsingApparentType2.ts ===
function foo<T extends { m(p: string): number }>(x: T): T {
>foo : <T extends { m(p: string): number; }>(x: T) => T
>T : T
>m : (p: string) => number
>p : string
>x : T
>T : T
>T : T
return undefined;
>undefined : undefined
}
foo({ m(x) { return x.length } });
>foo({ m(x) { return x.length } }) : { }
>foo : <T extends { m(p: string): number; }>(x: T) => T
>{ m(x) { return x.length } } : { m(x: string): number; }
>m : (x: string) => number
>x : string
>x.length : number
>x : string
>length : number

View File

@ -0,0 +1,56 @@
//// [inferentialTypingUsingApparentType3.ts]
interface Field<T> {
clean(input: T): T
}
class CharField implements Field<string> {
clean(input: string) {
return "Yup";
}
}
class NumberField implements Field<number> {
clean(input: number) {
return 123;
}
}
class ObjectField<A, T extends { [name: string]: Field<any> }> {
constructor(public fields: T) { }
}
var person = new ObjectField({
id: new NumberField(),
name: new CharField()
});
person.fields.id;
//// [inferentialTypingUsingApparentType3.js]
var CharField = (function () {
function CharField() {
}
CharField.prototype.clean = function (input) {
return "Yup";
};
return CharField;
})();
var NumberField = (function () {
function NumberField() {
}
NumberField.prototype.clean = function (input) {
return 123;
};
return NumberField;
})();
var ObjectField = (function () {
function ObjectField(fields) {
this.fields = fields;
}
return ObjectField;
})();
var person = new ObjectField({
id: new NumberField(),
name: new CharField()
});
person.fields.id;

View File

@ -0,0 +1,69 @@
=== tests/cases/compiler/inferentialTypingUsingApparentType3.ts ===
interface Field<T> {
>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 0, 16))
clean(input: T): T
>clean : Symbol(clean, Decl(inferentialTypingUsingApparentType3.ts, 0, 20))
>input : Symbol(input, Decl(inferentialTypingUsingApparentType3.ts, 1, 10))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 0, 16))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 0, 16))
}
class CharField implements Field<string> {
>CharField : Symbol(CharField, Decl(inferentialTypingUsingApparentType3.ts, 2, 1))
>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0))
clean(input: string) {
>clean : Symbol(clean, Decl(inferentialTypingUsingApparentType3.ts, 4, 42))
>input : Symbol(input, Decl(inferentialTypingUsingApparentType3.ts, 5, 10))
return "Yup";
}
}
class NumberField implements Field<number> {
>NumberField : Symbol(NumberField, Decl(inferentialTypingUsingApparentType3.ts, 8, 1))
>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0))
clean(input: number) {
>clean : Symbol(clean, Decl(inferentialTypingUsingApparentType3.ts, 10, 44))
>input : Symbol(input, Decl(inferentialTypingUsingApparentType3.ts, 11, 10))
return 123;
}
}
class ObjectField<A, T extends { [name: string]: Field<any> }> {
>ObjectField : Symbol(ObjectField, Decl(inferentialTypingUsingApparentType3.ts, 14, 1))
>A : Symbol(A, Decl(inferentialTypingUsingApparentType3.ts, 16, 18))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 16, 20))
>name : Symbol(name, Decl(inferentialTypingUsingApparentType3.ts, 16, 34))
>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0))
constructor(public fields: T) { }
>fields : Symbol(fields, Decl(inferentialTypingUsingApparentType3.ts, 17, 16))
>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 16, 20))
}
var person = new ObjectField({
>person : Symbol(person, Decl(inferentialTypingUsingApparentType3.ts, 20, 3))
>ObjectField : Symbol(ObjectField, Decl(inferentialTypingUsingApparentType3.ts, 14, 1))
id: new NumberField(),
>id : Symbol(id, Decl(inferentialTypingUsingApparentType3.ts, 20, 30))
>NumberField : Symbol(NumberField, Decl(inferentialTypingUsingApparentType3.ts, 8, 1))
name: new CharField()
>name : Symbol(name, Decl(inferentialTypingUsingApparentType3.ts, 21, 26))
>CharField : Symbol(CharField, Decl(inferentialTypingUsingApparentType3.ts, 2, 1))
});
person.fields.id;
>person.fields.id : Symbol(id, Decl(inferentialTypingUsingApparentType3.ts, 20, 30))
>person.fields : Symbol(ObjectField.fields, Decl(inferentialTypingUsingApparentType3.ts, 17, 16))
>person : Symbol(person, Decl(inferentialTypingUsingApparentType3.ts, 20, 3))
>fields : Symbol(ObjectField.fields, Decl(inferentialTypingUsingApparentType3.ts, 17, 16))
>id : Symbol(id, Decl(inferentialTypingUsingApparentType3.ts, 20, 30))

View File

@ -0,0 +1,75 @@
=== tests/cases/compiler/inferentialTypingUsingApparentType3.ts ===
interface Field<T> {
>Field : Field<T>
>T : T
clean(input: T): T
>clean : (input: T) => T
>input : T
>T : T
>T : T
}
class CharField implements Field<string> {
>CharField : CharField
>Field : Field<T>
clean(input: string) {
>clean : (input: string) => string
>input : string
return "Yup";
>"Yup" : string
}
}
class NumberField implements Field<number> {
>NumberField : NumberField
>Field : Field<T>
clean(input: number) {
>clean : (input: number) => number
>input : number
return 123;
>123 : number
}
}
class ObjectField<A, T extends { [name: string]: Field<any> }> {
>ObjectField : ObjectField<A, T>
>A : A
>T : T
>name : string
>Field : Field<T>
constructor(public fields: T) { }
>fields : T
>T : T
}
var person = new ObjectField({
>person : ObjectField<{}, { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }>
>new ObjectField({ id: new NumberField(), name: new CharField()}) : ObjectField<{}, { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }>
>ObjectField : typeof ObjectField
>{ id: new NumberField(), name: new CharField()} : { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }
id: new NumberField(),
>id : NumberField
>new NumberField() : NumberField
>NumberField : typeof NumberField
name: new CharField()
>name : CharField
>new CharField() : CharField
>CharField : typeof CharField
});
person.fields.id;
>person.fields.id : NumberField
>person.fields : { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }
>person : ObjectField<{}, { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }>
>fields : { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }
>id : NumberField

View File

@ -1,5 +1,5 @@
tests/cases/compiler/noErrorsInCallback.ts(4,19): error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'.
tests/cases/compiler/noErrorsInCallback.ts(6,23): error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'.
tests/cases/compiler/noErrorsInCallback.ts(4,19): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'.
tests/cases/compiler/noErrorsInCallback.ts(6,23): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'.
==== tests/cases/compiler/noErrorsInCallback.ts (2 errors) ====
@ -8,10 +8,10 @@ tests/cases/compiler/noErrorsInCallback.ts(6,23): error TS2345: Argument of type
}
var one = new Bar({}); // Error
~~
!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'.
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'.
[].forEach(() => {
var two = new Bar({}); // No error?
~~
!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'.
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'.
});

View File

@ -31,17 +31,17 @@ var foo: IFoo;
>IFoo : IFoo
foo.foo({ bar: null }, bar => null, bar => null);
>foo.foo({ bar: null }, bar => null, bar => null) : IBar
>foo.foo({ bar: null }, bar => null, bar => null) : { [x: string]: any; bar: any; }
>foo.foo : <TBar extends IBar>(bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar
>foo : IFoo
>foo : <TBar extends IBar>(bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar
>{ bar: null } : { [x: string]: null; bar: null; }
>bar : null
>null : null
>bar => null : (bar: IBar) => any
>bar : IBar
>bar => null : (bar: { [x: string]: any; bar: any; }) => any
>bar : { [x: string]: any; bar: any; }
>null : null
>bar => null : (bar: IBar) => any
>bar : IBar
>bar => null : (bar: { [x: string]: any; bar: any; }) => any
>bar : { [x: string]: any; bar: any; }
>null : null

View File

@ -1,4 +1,4 @@
tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints4.ts(13,12): error TS2345: Argument of type '{ length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'.
tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints4.ts(13,12): error TS2345: Argument of type '{ [x: number]: undefined; length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'.
==== tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints4.ts (1 errors) ====
@ -16,4 +16,4 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursi
var r = c.foo('');
var r2 = r({ length: 3, charAt: (x: number) => { '' } }); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '{ length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'.
!!! error TS2345: Argument of type '{ [x: number]: undefined; length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'.

View File

@ -0,0 +1,5 @@
function foo<T extends (p: string) => number>(x: T): T {
return undefined;
}
foo(x => x.length);

View File

@ -0,0 +1,5 @@
function foo<T extends { m(p: string): number }>(x: T): T {
return undefined;
}
foo({ m(x) { return x.length } });

View File

@ -0,0 +1,26 @@
interface Field<T> {
clean(input: T): T
}
class CharField implements Field<string> {
clean(input: string) {
return "Yup";
}
}
class NumberField implements Field<number> {
clean(input: number) {
return 123;
}
}
class ObjectField<A, T extends { [name: string]: Field<any> }> {
constructor(public fields: T) { }
}
var person = new ObjectField({
id: new NumberField(),
name: new CharField()
});
person.fields.id;