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) {
|
||||
const target = type.objectFlags & ObjectFlags.Instantiated ? type.target! : type;
|
||||
const declaration = type.objectFlags & ObjectFlags.Reference ? (<TypeReference>type).node! : type.symbol.declarations[0];
|
||||
const links = getNodeLinks(declaration);
|
||||
const target = type.objectFlags & ObjectFlags.Reference ? <DeferredTypeReference>links.resolvedType! :
|
||||
type.objectFlags & ObjectFlags.Instantiated ? type.target! : type;
|
||||
let typeParameters = links.outerTypeParameters;
|
||||
if (!typeParameters) {
|
||||
// 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)) :
|
||||
typeParameters;
|
||||
links.outerTypeParameters = typeParameters;
|
||||
if (typeParameters.length) {
|
||||
links.instantiations = new Map<string, Type>();
|
||||
links.instantiations.set(getTypeListId(typeParameters), target);
|
||||
}
|
||||
}
|
||||
if (typeParameters.length) {
|
||||
// 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 typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper));
|
||||
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) {
|
||||
const newMapper = createTypeMapper(typeParameters, typeArguments);
|
||||
result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((<DeferredTypeReference>type).target, (<DeferredTypeReference>type).node, newMapper) :
|
||||
target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) :
|
||||
instantiateAnonymousType(target, newMapper);
|
||||
links.instantiations!.set(id, result);
|
||||
target.instantiations.set(id, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -4847,7 +4847,6 @@ namespace ts {
|
|||
deferredNodes?: ESMap<NodeId, Node>; // Set of nodes whose checking has been deferred
|
||||
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
|
||||
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
|
||||
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.
|
||||
|
@ -5141,6 +5140,8 @@ namespace ts {
|
|||
node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
|
||||
/* @internal */
|
||||
mapper?: TypeMapper;
|
||||
/* @internal */
|
||||
instantiations?: ESMap<string, Type>; // Instantiations of generic type alias (undefined if non-generic)
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -5221,6 +5222,7 @@ namespace ts {
|
|||
export interface AnonymousType extends ObjectType {
|
||||
target?: AnonymousType; // Instantiation target
|
||||
mapper?: TypeMapper; // Instantiation mapper
|
||||
instantiations?: ESMap<string, Type>; // Instantiations of generic type alias (undefined if non-generic)
|
||||
}
|
||||
|
||||
/* @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