Merge pull request #29647 from Microsoft/noConstraintsDuringInference

Only check constraints in final phase of type inference
This commit is contained in:
Anders Hejlsberg 2019-02-01 10:54:08 -08:00 committed by GitHub
commit 8827bed0e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 218 additions and 2 deletions

View file

@ -14113,7 +14113,9 @@ namespace ts {
function mapper(t: Type): Type {
for (let i = 0; i < inferences.length; i++) {
if (t === inferences[i].typeParameter) {
inferences[i].isFixed = true;
if (!(context.flags & InferenceFlags.NoFixing)) {
inferences[i].isFixed = true;
}
return getInferredType(context, i);
}
}
@ -14839,10 +14841,12 @@ namespace ts {
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
if (constraint) {
context.flags |= InferenceFlags.NoFixing;
const instantiatedConstraint = instantiateType(constraint, context);
if (!context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
inference.inferredType = inferredType = instantiatedConstraint;
}
context.flags &= ~InferenceFlags.NoFixing;
}
}

View file

@ -4341,6 +4341,7 @@ namespace ts {
None = 0, // No special inference behaviors
NoDefault = 1 << 0, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType)
AnyDefault = 1 << 1, // Infer anyType for no inferences (otherwise emptyObjectType)
NoFixing = 1 << 2, // Disable type parameter fixing
}
/**

View file

@ -0,0 +1,52 @@
//// [inferenceAndSelfReferentialConstraint.ts]
// @strict
// Repro from #29520
type Test<K extends keyof any> = {
[P in K | "foo"]: P extends "foo" ? true : () => any
}
function test<T extends Test<keyof T>>(arg: T) {
return arg;
}
const res1 = test({
foo: true,
bar() {
}
});
const res2 = test({
foo: true,
bar: function () {
}
});
const res3 = test({
foo: true,
bar: () => {
}
});
//// [inferenceAndSelfReferentialConstraint.js]
// @strict
function test(arg) {
return arg;
}
var res1 = test({
foo: true,
bar: function () {
}
});
var res2 = test({
foo: true,
bar: function () {
}
});
var res3 = test({
foo: true,
bar: function () {
}
});

View file

@ -0,0 +1,63 @@
=== tests/cases/compiler/inferenceAndSelfReferentialConstraint.ts ===
// @strict
// Repro from #29520
type Test<K extends keyof any> = {
>Test : Symbol(Test, Decl(inferenceAndSelfReferentialConstraint.ts, 0, 0))
>K : Symbol(K, Decl(inferenceAndSelfReferentialConstraint.ts, 4, 10))
[P in K | "foo"]: P extends "foo" ? true : () => any
>P : Symbol(P, Decl(inferenceAndSelfReferentialConstraint.ts, 5, 3))
>K : Symbol(K, Decl(inferenceAndSelfReferentialConstraint.ts, 4, 10))
>P : Symbol(P, Decl(inferenceAndSelfReferentialConstraint.ts, 5, 3))
}
function test<T extends Test<keyof T>>(arg: T) {
>test : Symbol(test, Decl(inferenceAndSelfReferentialConstraint.ts, 6, 1))
>T : Symbol(T, Decl(inferenceAndSelfReferentialConstraint.ts, 8, 14))
>Test : Symbol(Test, Decl(inferenceAndSelfReferentialConstraint.ts, 0, 0))
>T : Symbol(T, Decl(inferenceAndSelfReferentialConstraint.ts, 8, 14))
>arg : Symbol(arg, Decl(inferenceAndSelfReferentialConstraint.ts, 8, 39))
>T : Symbol(T, Decl(inferenceAndSelfReferentialConstraint.ts, 8, 14))
return arg;
>arg : Symbol(arg, Decl(inferenceAndSelfReferentialConstraint.ts, 8, 39))
}
const res1 = test({
>res1 : Symbol(res1, Decl(inferenceAndSelfReferentialConstraint.ts, 12, 5))
>test : Symbol(test, Decl(inferenceAndSelfReferentialConstraint.ts, 6, 1))
foo: true,
>foo : Symbol(foo, Decl(inferenceAndSelfReferentialConstraint.ts, 12, 19))
bar() {
>bar : Symbol(bar, Decl(inferenceAndSelfReferentialConstraint.ts, 13, 12))
}
});
const res2 = test({
>res2 : Symbol(res2, Decl(inferenceAndSelfReferentialConstraint.ts, 18, 5))
>test : Symbol(test, Decl(inferenceAndSelfReferentialConstraint.ts, 6, 1))
foo: true,
>foo : Symbol(foo, Decl(inferenceAndSelfReferentialConstraint.ts, 18, 19))
bar: function () {
>bar : Symbol(bar, Decl(inferenceAndSelfReferentialConstraint.ts, 19, 12))
}
});
const res3 = test({
>res3 : Symbol(res3, Decl(inferenceAndSelfReferentialConstraint.ts, 24, 5))
>test : Symbol(test, Decl(inferenceAndSelfReferentialConstraint.ts, 6, 1))
foo: true,
>foo : Symbol(foo, Decl(inferenceAndSelfReferentialConstraint.ts, 24, 19))
bar: () => {
>bar : Symbol(bar, Decl(inferenceAndSelfReferentialConstraint.ts, 25, 12))
}
});

View file

@ -0,0 +1,67 @@
=== tests/cases/compiler/inferenceAndSelfReferentialConstraint.ts ===
// @strict
// Repro from #29520
type Test<K extends keyof any> = {
>Test : Test<K>
[P in K | "foo"]: P extends "foo" ? true : () => any
>true : true
}
function test<T extends Test<keyof T>>(arg: T) {
>test : <T extends Test<keyof T>>(arg: T) => T
>arg : T
return arg;
>arg : T
}
const res1 = test({
>res1 : { foo: true; bar(): void; }
>test({ foo: true, bar() { }}) : { foo: true; bar(): void; }
>test : <T extends Test<keyof T>>(arg: T) => T
>{ foo: true, bar() { }} : { foo: true; bar(): void; }
foo: true,
>foo : true
>true : true
bar() {
>bar : () => void
}
});
const res2 = test({
>res2 : { foo: true; bar: () => void; }
>test({ foo: true, bar: function () { }}) : { foo: true; bar: () => void; }
>test : <T extends Test<keyof T>>(arg: T) => T
>{ foo: true, bar: function () { }} : { foo: true; bar: () => void; }
foo: true,
>foo : true
>true : true
bar: function () {
>bar : () => void
>function () { } : () => void
}
});
const res3 = test({
>res3 : { foo: true; bar: () => void; }
>test({ foo: true, bar: () => { }}) : { foo: true; bar: () => void; }
>test : <T extends Test<keyof T>>(arg: T) => T
>{ foo: true, bar: () => { }} : { foo: true; bar: () => void; }
foo: true,
>foo : true
>true : true
bar: () => {
>bar : () => void
>() => { } : () => void
}
});

View file

@ -52,7 +52,7 @@ function f(t, u, v, w, x) {
}
f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope');
>f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope') : string | number
>f({ a: 12, b: 'hi', c: null }, undefined, { c: false, d: 12, b: undefined }, 101, 'nope') : 101 | "nope"
>f : <T extends { a: number; b: string; }, U, V extends { c: boolean; }, W, X>(t: T, u: U, v: V, w: W, x: X) => W | X
>{ a: 12, b: 'hi', c: null } : { a: number; b: string; c: null; }
>a : number

View file

@ -0,0 +1,29 @@
// @strict
// Repro from #29520
type Test<K extends keyof any> = {
[P in K | "foo"]: P extends "foo" ? true : () => any
}
function test<T extends Test<keyof T>>(arg: T) {
return arg;
}
const res1 = test({
foo: true,
bar() {
}
});
const res2 = test({
foo: true,
bar: function () {
}
});
const res3 = test({
foo: true,
bar: () => {
}
});