Create returnOnlySignature only when inferences will possibly be made (#35173)

* Create returnOnlySignature only when inferences will possibly be made

* Add regression test

* Accept new baselines
This commit is contained in:
Anders Hejlsberg 2019-11-25 15:05:53 -08:00 committed by GitHub
parent 0c17476d09
commit 0c2c58c42f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 491 additions and 8 deletions

View file

@ -26129,15 +26129,19 @@ namespace ts {
if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) {
// Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage
if (!getEffectiveReturnTypeNode(node) && hasContextSensitiveReturnExpression(node)) {
const links = getNodeLinks(node);
if (links.contextFreeType) {
return links.contextFreeType;
// Return plain anyFunctionType if there is no possibility we'll make inferences from the return type
const contextualSignature = getContextualSignature(node);
if (contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature))) {
const links = getNodeLinks(node);
if (links.contextFreeType) {
return links.contextFreeType;
}
const returnType = getReturnTypeFromBody(node, checkMode);
const returnOnlySignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None);
const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, undefined, undefined);
returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType;
return links.contextFreeType = returnOnlyType;
}
const returnType = getReturnTypeFromBody(node, checkMode);
const returnOnlySignature = createSignature(undefined, undefined, undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None);
const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, undefined, undefined);
returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType;
return links.contextFreeType = returnOnlyType;
}
return anyFunctionType;
}

View file

@ -0,0 +1,87 @@
//// [contextSensitiveReturnTypeInference.ts]
// Repro from #34849
interface IData {
bar: boolean
}
declare function test<TDependencies>(
getter: (deps: TDependencies, data: IData) => any,
deps: TDependencies,
): any
const DEPS = {
foo: 1
}
test(
(deps, data) => ({
fn1: function() { return deps.foo },
fn2: data.bar
}),
DEPS
);
test(
(deps: typeof DEPS, data) => ({
fn1: function() { return deps.foo },
fn2: data.bar
}),
DEPS
);
test(
(deps, data) => ({
fn1: () => deps.foo,
fn2: data.bar
}),
DEPS
);
test(
(deps, data) => {
return {
fn1() { return deps.foo },
fn2: data.bar
}
},
DEPS
);
test(
(deps) => ({
fn1() { return deps.foo },
fn2: 1
}),
DEPS
);
//// [contextSensitiveReturnTypeInference.js]
"use strict";
// Repro from #34849
var DEPS = {
foo: 1
};
test(function (deps, data) { return ({
fn1: function () { return deps.foo; },
fn2: data.bar
}); }, DEPS);
test(function (deps, data) { return ({
fn1: function () { return deps.foo; },
fn2: data.bar
}); }, DEPS);
test(function (deps, data) { return ({
fn1: function () { return deps.foo; },
fn2: data.bar
}); }, DEPS);
test(function (deps, data) {
return {
fn1: function () { return deps.foo; },
fn2: data.bar
};
}, DEPS);
test(function (deps) { return ({
fn1: function () { return deps.foo; },
fn2: 1
}); }, DEPS);

View file

@ -0,0 +1,157 @@
=== tests/cases/compiler/contextSensitiveReturnTypeInference.ts ===
// Repro from #34849
interface IData {
>IData : Symbol(IData, Decl(contextSensitiveReturnTypeInference.ts, 0, 0))
bar: boolean
>bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
}
declare function test<TDependencies>(
>test : Symbol(test, Decl(contextSensitiveReturnTypeInference.ts, 4, 1))
>TDependencies : Symbol(TDependencies, Decl(contextSensitiveReturnTypeInference.ts, 6, 22))
getter: (deps: TDependencies, data: IData) => any,
>getter : Symbol(getter, Decl(contextSensitiveReturnTypeInference.ts, 6, 37))
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 7, 11))
>TDependencies : Symbol(TDependencies, Decl(contextSensitiveReturnTypeInference.ts, 6, 22))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 7, 31))
>IData : Symbol(IData, Decl(contextSensitiveReturnTypeInference.ts, 0, 0))
deps: TDependencies,
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 7, 52))
>TDependencies : Symbol(TDependencies, Decl(contextSensitiveReturnTypeInference.ts, 6, 22))
): any
const DEPS = {
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
foo: 1
>foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
}
test(
>test : Symbol(test, Decl(contextSensitiveReturnTypeInference.ts, 4, 1))
(deps, data) => ({
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 16, 3))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 16, 8))
fn1: function() { return deps.foo },
>fn1 : Symbol(fn1, Decl(contextSensitiveReturnTypeInference.ts, 16, 20))
>deps.foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 16, 3))
>foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
fn2: data.bar
>fn2 : Symbol(fn2, Decl(contextSensitiveReturnTypeInference.ts, 17, 40))
>data.bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 16, 8))
>bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
}),
DEPS
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
);
test(
>test : Symbol(test, Decl(contextSensitiveReturnTypeInference.ts, 4, 1))
(deps: typeof DEPS, data) => ({
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 24, 3))
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 24, 21))
fn1: function() { return deps.foo },
>fn1 : Symbol(fn1, Decl(contextSensitiveReturnTypeInference.ts, 24, 33))
>deps.foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 24, 3))
>foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
fn2: data.bar
>fn2 : Symbol(fn2, Decl(contextSensitiveReturnTypeInference.ts, 25, 40))
>data.bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 24, 21))
>bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
}),
DEPS
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
);
test(
>test : Symbol(test, Decl(contextSensitiveReturnTypeInference.ts, 4, 1))
(deps, data) => ({
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 32, 3))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 32, 8))
fn1: () => deps.foo,
>fn1 : Symbol(fn1, Decl(contextSensitiveReturnTypeInference.ts, 32, 20))
>deps.foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 32, 3))
>foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
fn2: data.bar
>fn2 : Symbol(fn2, Decl(contextSensitiveReturnTypeInference.ts, 33, 24))
>data.bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 32, 8))
>bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
}),
DEPS
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
);
test(
>test : Symbol(test, Decl(contextSensitiveReturnTypeInference.ts, 4, 1))
(deps, data) => {
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 40, 3))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 40, 8))
return {
fn1() { return deps.foo },
>fn1 : Symbol(fn1, Decl(contextSensitiveReturnTypeInference.ts, 41, 12))
>deps.foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 40, 3))
>foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
fn2: data.bar
>fn2 : Symbol(fn2, Decl(contextSensitiveReturnTypeInference.ts, 42, 32))
>data.bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
>data : Symbol(data, Decl(contextSensitiveReturnTypeInference.ts, 40, 8))
>bar : Symbol(IData.bar, Decl(contextSensitiveReturnTypeInference.ts, 2, 17))
}
},
DEPS
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
);
test(
>test : Symbol(test, Decl(contextSensitiveReturnTypeInference.ts, 4, 1))
(deps) => ({
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 50, 3))
fn1() { return deps.foo },
>fn1 : Symbol(fn1, Decl(contextSensitiveReturnTypeInference.ts, 50, 14))
>deps.foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
>deps : Symbol(deps, Decl(contextSensitiveReturnTypeInference.ts, 50, 3))
>foo : Symbol(foo, Decl(contextSensitiveReturnTypeInference.ts, 11, 14))
fn2: 1
>fn2 : Symbol(fn2, Decl(contextSensitiveReturnTypeInference.ts, 51, 30))
}),
DEPS
>DEPS : Symbol(DEPS, Decl(contextSensitiveReturnTypeInference.ts, 11, 5))
);

View file

@ -0,0 +1,177 @@
=== tests/cases/compiler/contextSensitiveReturnTypeInference.ts ===
// Repro from #34849
interface IData {
bar: boolean
>bar : boolean
}
declare function test<TDependencies>(
>test : <TDependencies>(getter: (deps: TDependencies, data: IData) => any, deps: TDependencies) => any
getter: (deps: TDependencies, data: IData) => any,
>getter : (deps: TDependencies, data: IData) => any
>deps : TDependencies
>data : IData
deps: TDependencies,
>deps : TDependencies
): any
const DEPS = {
>DEPS : { foo: number; }
>{ foo: 1} : { foo: number; }
foo: 1
>foo : number
>1 : 1
}
test(
>test( (deps, data) => ({ fn1: function() { return deps.foo }, fn2: data.bar }), DEPS) : any
>test : <TDependencies>(getter: (deps: TDependencies, data: IData) => any, deps: TDependencies) => any
(deps, data) => ({
>(deps, data) => ({ fn1: function() { return deps.foo }, fn2: data.bar }) : (deps: { foo: number; }, data: IData) => { fn1: () => number; fn2: boolean; }
>deps : { foo: number; }
>data : IData
>({ fn1: function() { return deps.foo }, fn2: data.bar }) : { fn1: () => number; fn2: boolean; }
>{ fn1: function() { return deps.foo }, fn2: data.bar } : { fn1: () => number; fn2: boolean; }
fn1: function() { return deps.foo },
>fn1 : () => number
>function() { return deps.foo } : () => number
>deps.foo : number
>deps : { foo: number; }
>foo : number
fn2: data.bar
>fn2 : boolean
>data.bar : boolean
>data : IData
>bar : boolean
}),
DEPS
>DEPS : { foo: number; }
);
test(
>test( (deps: typeof DEPS, data) => ({ fn1: function() { return deps.foo }, fn2: data.bar }), DEPS) : any
>test : <TDependencies>(getter: (deps: TDependencies, data: IData) => any, deps: TDependencies) => any
(deps: typeof DEPS, data) => ({
>(deps: typeof DEPS, data) => ({ fn1: function() { return deps.foo }, fn2: data.bar }) : (deps: { foo: number; }, data: IData) => { fn1: () => number; fn2: boolean; }
>deps : { foo: number; }
>DEPS : { foo: number; }
>data : IData
>({ fn1: function() { return deps.foo }, fn2: data.bar }) : { fn1: () => number; fn2: boolean; }
>{ fn1: function() { return deps.foo }, fn2: data.bar } : { fn1: () => number; fn2: boolean; }
fn1: function() { return deps.foo },
>fn1 : () => number
>function() { return deps.foo } : () => number
>deps.foo : number
>deps : { foo: number; }
>foo : number
fn2: data.bar
>fn2 : boolean
>data.bar : boolean
>data : IData
>bar : boolean
}),
DEPS
>DEPS : { foo: number; }
);
test(
>test( (deps, data) => ({ fn1: () => deps.foo, fn2: data.bar }), DEPS) : any
>test : <TDependencies>(getter: (deps: TDependencies, data: IData) => any, deps: TDependencies) => any
(deps, data) => ({
>(deps, data) => ({ fn1: () => deps.foo, fn2: data.bar }) : (deps: { foo: number; }, data: IData) => { fn1: () => number; fn2: boolean; }
>deps : { foo: number; }
>data : IData
>({ fn1: () => deps.foo, fn2: data.bar }) : { fn1: () => number; fn2: boolean; }
>{ fn1: () => deps.foo, fn2: data.bar } : { fn1: () => number; fn2: boolean; }
fn1: () => deps.foo,
>fn1 : () => number
>() => deps.foo : () => number
>deps.foo : number
>deps : { foo: number; }
>foo : number
fn2: data.bar
>fn2 : boolean
>data.bar : boolean
>data : IData
>bar : boolean
}),
DEPS
>DEPS : { foo: number; }
);
test(
>test( (deps, data) => { return { fn1() { return deps.foo }, fn2: data.bar } }, DEPS) : any
>test : <TDependencies>(getter: (deps: TDependencies, data: IData) => any, deps: TDependencies) => any
(deps, data) => {
>(deps, data) => { return { fn1() { return deps.foo }, fn2: data.bar } } : (deps: { foo: number; }, data: IData) => { fn1(): number; fn2: boolean; }
>deps : { foo: number; }
>data : IData
return {
>{ fn1() { return deps.foo }, fn2: data.bar } : { fn1(): number; fn2: boolean; }
fn1() { return deps.foo },
>fn1 : () => number
>deps.foo : number
>deps : { foo: number; }
>foo : number
fn2: data.bar
>fn2 : boolean
>data.bar : boolean
>data : IData
>bar : boolean
}
},
DEPS
>DEPS : { foo: number; }
);
test(
>test( (deps) => ({ fn1() { return deps.foo }, fn2: 1 }), DEPS) : any
>test : <TDependencies>(getter: (deps: TDependencies, data: IData) => any, deps: TDependencies) => any
(deps) => ({
>(deps) => ({ fn1() { return deps.foo }, fn2: 1 }) : (deps: { foo: number; }) => { fn1(): number; fn2: number; }
>deps : { foo: number; }
>({ fn1() { return deps.foo }, fn2: 1 }) : { fn1(): number; fn2: number; }
>{ fn1() { return deps.foo }, fn2: 1 } : { fn1(): number; fn2: number; }
fn1() { return deps.foo },
>fn1 : () => number
>deps.foo : number
>deps : { foo: number; }
>foo : number
fn2: 1
>fn2 : number
>1 : 1
}),
DEPS
>DEPS : { foo: number; }
);

View file

@ -0,0 +1,58 @@
// @strict: true
// Repro from #34849
interface IData {
bar: boolean
}
declare function test<TDependencies>(
getter: (deps: TDependencies, data: IData) => any,
deps: TDependencies,
): any
const DEPS = {
foo: 1
}
test(
(deps, data) => ({
fn1: function() { return deps.foo },
fn2: data.bar
}),
DEPS
);
test(
(deps: typeof DEPS, data) => ({
fn1: function() { return deps.foo },
fn2: data.bar
}),
DEPS
);
test(
(deps, data) => ({
fn1: () => deps.foo,
fn2: data.bar
}),
DEPS
);
test(
(deps, data) => {
return {
fn1() { return deps.foo },
fn2: data.bar
}
},
DEPS
);
test(
(deps) => ({
fn1() { return deps.foo },
fn2: 1
}),
DEPS
);