Move anonymous type instantiation cache from AST node to root type (#41084)
* Move anonymous type instantiation cache from AST node to root type * Use "root" type reference as cache location for deferred type references * Add test Co-authored-by: Andrew Branch <andrew@wheream.io>
This commit is contained in:
parent
cdf9c3b595
commit
3918e6c535
|
@ -15046,9 +15046,10 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) {
|
function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) {
|
||||||
const target = type.objectFlags & ObjectFlags.Instantiated ? type.target! : type;
|
|
||||||
const declaration = type.objectFlags & ObjectFlags.Reference ? (<TypeReference>type).node! : type.symbol.declarations[0];
|
const declaration = type.objectFlags & ObjectFlags.Reference ? (<TypeReference>type).node! : type.symbol.declarations[0];
|
||||||
const links = getNodeLinks(declaration);
|
const links = getNodeLinks(declaration);
|
||||||
|
const target = type.objectFlags & ObjectFlags.Reference ? <DeferredTypeReference>links.resolvedType! :
|
||||||
|
type.objectFlags & ObjectFlags.Instantiated ? type.target! : type;
|
||||||
let typeParameters = links.outerTypeParameters;
|
let typeParameters = links.outerTypeParameters;
|
||||||
if (!typeParameters) {
|
if (!typeParameters) {
|
||||||
// The first time an anonymous type is instantiated we compute and store a list of the type
|
// The first time an anonymous type is instantiated we compute and store a list of the type
|
||||||
|
@ -15065,10 +15066,6 @@ namespace ts {
|
||||||
filter(typeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
|
filter(typeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
|
||||||
typeParameters;
|
typeParameters;
|
||||||
links.outerTypeParameters = typeParameters;
|
links.outerTypeParameters = typeParameters;
|
||||||
if (typeParameters.length) {
|
|
||||||
links.instantiations = new Map<string, Type>();
|
|
||||||
links.instantiations.set(getTypeListId(typeParameters), target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (typeParameters.length) {
|
if (typeParameters.length) {
|
||||||
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
|
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
|
||||||
|
@ -15077,13 +15074,17 @@ namespace ts {
|
||||||
const combinedMapper = combineTypeMappers(type.mapper, mapper);
|
const combinedMapper = combineTypeMappers(type.mapper, mapper);
|
||||||
const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper));
|
const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper));
|
||||||
const id = getTypeListId(typeArguments);
|
const id = getTypeListId(typeArguments);
|
||||||
let result = links.instantiations!.get(id);
|
if (!target.instantiations) {
|
||||||
|
target.instantiations = new Map<string, Type>();
|
||||||
|
target.instantiations.set(getTypeListId(typeParameters), target);
|
||||||
|
}
|
||||||
|
let result = target.instantiations.get(id);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
const newMapper = createTypeMapper(typeParameters, typeArguments);
|
const newMapper = createTypeMapper(typeParameters, typeArguments);
|
||||||
result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((<DeferredTypeReference>type).target, (<DeferredTypeReference>type).node, newMapper) :
|
result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((<DeferredTypeReference>type).target, (<DeferredTypeReference>type).node, newMapper) :
|
||||||
target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) :
|
target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) :
|
||||||
instantiateAnonymousType(target, newMapper);
|
instantiateAnonymousType(target, newMapper);
|
||||||
links.instantiations!.set(id, result);
|
target.instantiations.set(id, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4847,7 +4847,6 @@ namespace ts {
|
||||||
deferredNodes?: ESMap<NodeId, Node>; // Set of nodes whose checking has been deferred
|
deferredNodes?: ESMap<NodeId, Node>; // Set of nodes whose checking has been deferred
|
||||||
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
|
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
|
||||||
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
|
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
|
||||||
instantiations?: ESMap<string, Type>; // Instantiations of generic type alias (undefined if non-generic)
|
|
||||||
isExhaustive?: boolean; // Is node an exhaustive switch statement
|
isExhaustive?: boolean; // Is node an exhaustive switch statement
|
||||||
skipDirectInference?: true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type
|
skipDirectInference?: true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type
|
||||||
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
|
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
|
||||||
|
@ -5141,6 +5140,8 @@ namespace ts {
|
||||||
node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
|
node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
|
||||||
/* @internal */
|
/* @internal */
|
||||||
mapper?: TypeMapper;
|
mapper?: TypeMapper;
|
||||||
|
/* @internal */
|
||||||
|
instantiations?: ESMap<string, Type>; // Instantiations of generic type alias (undefined if non-generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @internal */
|
/* @internal */
|
||||||
|
@ -5221,6 +5222,7 @@ namespace ts {
|
||||||
export interface AnonymousType extends ObjectType {
|
export interface AnonymousType extends ObjectType {
|
||||||
target?: AnonymousType; // Instantiation target
|
target?: AnonymousType; // Instantiation target
|
||||||
mapper?: TypeMapper; // Instantiation mapper
|
mapper?: TypeMapper; // Instantiation mapper
|
||||||
|
instantiations?: ESMap<string, Type>; // Instantiations of generic type alias (undefined if non-generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @internal */
|
/* @internal */
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
//// [objectInstantiationFromUnionSpread.ts]
|
||||||
|
// #40995
|
||||||
|
|
||||||
|
interface Success {
|
||||||
|
isSuccess: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Fail {
|
||||||
|
isSuccess: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item = Success | Fail;
|
||||||
|
|
||||||
|
function f1(a: Item[]) {
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function f2<T>(a: Item[]) {
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// [objectInstantiationFromUnionSpread.js]
|
||||||
|
// #40995
|
||||||
|
var __assign = (this && this.__assign) || function () {
|
||||||
|
__assign = Object.assign || function(t) {
|
||||||
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||||
|
s = arguments[i];
|
||||||
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||||
|
t[p] = s[p];
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
return __assign.apply(this, arguments);
|
||||||
|
};
|
||||||
|
function f1(a) {
|
||||||
|
a.map(function (item) { return (__assign({}, item)); }).filter(function (value) { });
|
||||||
|
}
|
||||||
|
function f2(a) {
|
||||||
|
a.map(function (item) { return (__assign({}, item)); }).filter(function (value) { });
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
=== tests/cases/compiler/objectInstantiationFromUnionSpread.ts ===
|
||||||
|
// #40995
|
||||||
|
|
||||||
|
interface Success {
|
||||||
|
>Success : Symbol(Success, Decl(objectInstantiationFromUnionSpread.ts, 0, 0))
|
||||||
|
|
||||||
|
isSuccess: true;
|
||||||
|
>isSuccess : Symbol(Success.isSuccess, Decl(objectInstantiationFromUnionSpread.ts, 2, 19))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Fail {
|
||||||
|
>Fail : Symbol(Fail, Decl(objectInstantiationFromUnionSpread.ts, 4, 1))
|
||||||
|
|
||||||
|
isSuccess: false;
|
||||||
|
>isSuccess : Symbol(Fail.isSuccess, Decl(objectInstantiationFromUnionSpread.ts, 6, 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item = Success | Fail;
|
||||||
|
>Item : Symbol(Item, Decl(objectInstantiationFromUnionSpread.ts, 8, 1))
|
||||||
|
>Success : Symbol(Success, Decl(objectInstantiationFromUnionSpread.ts, 0, 0))
|
||||||
|
>Fail : Symbol(Fail, Decl(objectInstantiationFromUnionSpread.ts, 4, 1))
|
||||||
|
|
||||||
|
function f1(a: Item[]) {
|
||||||
|
>f1 : Symbol(f1, Decl(objectInstantiationFromUnionSpread.ts, 10, 27))
|
||||||
|
>a : Symbol(a, Decl(objectInstantiationFromUnionSpread.ts, 12, 12))
|
||||||
|
>Item : Symbol(Item, Decl(objectInstantiationFromUnionSpread.ts, 8, 1))
|
||||||
|
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
>a.map(item => ({ ...item })).filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>a.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>a : Symbol(a, Decl(objectInstantiationFromUnionSpread.ts, 12, 12))
|
||||||
|
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>item : Symbol(item, Decl(objectInstantiationFromUnionSpread.ts, 13, 8))
|
||||||
|
>item : Symbol(item, Decl(objectInstantiationFromUnionSpread.ts, 13, 8))
|
||||||
|
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>value : Symbol(value, Decl(objectInstantiationFromUnionSpread.ts, 13, 38))
|
||||||
|
}
|
||||||
|
|
||||||
|
function f2<T>(a: Item[]) {
|
||||||
|
>f2 : Symbol(f2, Decl(objectInstantiationFromUnionSpread.ts, 14, 1))
|
||||||
|
>T : Symbol(T, Decl(objectInstantiationFromUnionSpread.ts, 16, 12))
|
||||||
|
>a : Symbol(a, Decl(objectInstantiationFromUnionSpread.ts, 16, 15))
|
||||||
|
>Item : Symbol(Item, Decl(objectInstantiationFromUnionSpread.ts, 8, 1))
|
||||||
|
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
>a.map(item => ({ ...item })).filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>a.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>a : Symbol(a, Decl(objectInstantiationFromUnionSpread.ts, 16, 15))
|
||||||
|
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
|
||||||
|
>item : Symbol(item, Decl(objectInstantiationFromUnionSpread.ts, 17, 8))
|
||||||
|
>item : Symbol(item, Decl(objectInstantiationFromUnionSpread.ts, 17, 8))
|
||||||
|
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||||
|
>value : Symbol(value, Decl(objectInstantiationFromUnionSpread.ts, 17, 38))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
=== tests/cases/compiler/objectInstantiationFromUnionSpread.ts ===
|
||||||
|
// #40995
|
||||||
|
|
||||||
|
interface Success {
|
||||||
|
isSuccess: true;
|
||||||
|
>isSuccess : true
|
||||||
|
>true : true
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Fail {
|
||||||
|
isSuccess: false;
|
||||||
|
>isSuccess : false
|
||||||
|
>false : false
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item = Success | Fail;
|
||||||
|
>Item : Item
|
||||||
|
|
||||||
|
function f1(a: Item[]) {
|
||||||
|
>f1 : (a: Item[]) => void
|
||||||
|
>a : Item[]
|
||||||
|
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
>a.map(item => ({ ...item })).filter(value => {}) : ({ isSuccess: true; } | { isSuccess: false; })[]
|
||||||
|
>a.map(item => ({ ...item })).filter : { <S extends { isSuccess: true; } | { isSuccess: false; }>(predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => value is S, thisArg?: any): S[]; (predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => unknown, thisArg?: any): ({ isSuccess: true; } | { isSuccess: false; })[]; }
|
||||||
|
>a.map(item => ({ ...item })) : ({ isSuccess: true; } | { isSuccess: false; })[]
|
||||||
|
>a.map : <U>(callbackfn: (value: Item, index: number, array: Item[]) => U, thisArg?: any) => U[]
|
||||||
|
>a : Item[]
|
||||||
|
>map : <U>(callbackfn: (value: Item, index: number, array: Item[]) => U, thisArg?: any) => U[]
|
||||||
|
>item => ({ ...item }) : (item: Item) => { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
>item : Item
|
||||||
|
>({ ...item }) : { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
>{ ...item } : { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
>item : Item
|
||||||
|
>filter : { <S extends { isSuccess: true; } | { isSuccess: false; }>(predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => value is S, thisArg?: any): S[]; (predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => unknown, thisArg?: any): ({ isSuccess: true; } | { isSuccess: false; })[]; }
|
||||||
|
>value => {} : (value: { isSuccess: true; } | { isSuccess: false; }) => void
|
||||||
|
>value : { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function f2<T>(a: Item[]) {
|
||||||
|
>f2 : <T>(a: Item[]) => void
|
||||||
|
>a : Item[]
|
||||||
|
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
>a.map(item => ({ ...item })).filter(value => {}) : ({ isSuccess: true; } | { isSuccess: false; })[]
|
||||||
|
>a.map(item => ({ ...item })).filter : { <S extends { isSuccess: true; } | { isSuccess: false; }>(predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => value is S, thisArg?: any): S[]; (predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => unknown, thisArg?: any): ({ isSuccess: true; } | { isSuccess: false; })[]; }
|
||||||
|
>a.map(item => ({ ...item })) : ({ isSuccess: true; } | { isSuccess: false; })[]
|
||||||
|
>a.map : <U>(callbackfn: (value: Item, index: number, array: Item[]) => U, thisArg?: any) => U[]
|
||||||
|
>a : Item[]
|
||||||
|
>map : <U>(callbackfn: (value: Item, index: number, array: Item[]) => U, thisArg?: any) => U[]
|
||||||
|
>item => ({ ...item }) : (item: Item) => { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
>item : Item
|
||||||
|
>({ ...item }) : { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
>{ ...item } : { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
>item : Item
|
||||||
|
>filter : { <S extends { isSuccess: true; } | { isSuccess: false; }>(predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => value is S, thisArg?: any): S[]; (predicate: (value: { isSuccess: true; } | { isSuccess: false; }, index: number, array: ({ isSuccess: true; } | { isSuccess: false; })[]) => unknown, thisArg?: any): ({ isSuccess: true; } | { isSuccess: false; })[]; }
|
||||||
|
>value => {} : (value: { isSuccess: true; } | { isSuccess: false; }) => void
|
||||||
|
>value : { isSuccess: true; } | { isSuccess: false; }
|
||||||
|
}
|
||||||
|
|
21
tests/cases/compiler/objectInstantiationFromUnionSpread.ts
Normal file
21
tests/cases/compiler/objectInstantiationFromUnionSpread.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// @strictFunctionTypes: true
|
||||||
|
|
||||||
|
// #40995
|
||||||
|
|
||||||
|
interface Success {
|
||||||
|
isSuccess: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Fail {
|
||||||
|
isSuccess: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Item = Success | Fail;
|
||||||
|
|
||||||
|
function f1(a: Item[]) {
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function f2<T>(a: Item[]) {
|
||||||
|
a.map(item => ({ ...item })).filter(value => {});
|
||||||
|
}
|
Loading…
Reference in a new issue