mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-22 16:52:14 -06:00
Get it working:
1. Actually return the cached result! 2. Unnest worker function. 3. Improve all the names. 4. Pre-set the cache to undefined to avoid loops. (Not sure this is needed, though.) 5. Make the new type internal to avoid baseline changes. 6. Cut off recursion in the printing of recursive deferred mapped types. Note that (6) required introducing a new stack that is exactly like mappedTypeStack. I think the cache may actually be needed here, not in the creation of the deferred type.
This commit is contained in:
parent
7d1a980ad2
commit
05de0a7da3
@ -335,6 +335,7 @@ namespace ts {
|
||||
|
||||
const globals = createSymbolTable();
|
||||
const deferredInferenceCache = createMap<Type | undefined>();
|
||||
const deferredMappedTypeInstantiationStack: string[] = [];
|
||||
let ambientModulesCache: Symbol[] | undefined;
|
||||
/**
|
||||
* List of every ambient module with a "*" wildcard.
|
||||
@ -2867,7 +2868,23 @@ namespace ts {
|
||||
}
|
||||
|
||||
for (const propertySymbol of properties) {
|
||||
const propertyType = getTypeOfSymbol(propertySymbol);
|
||||
let propertyType: Type;
|
||||
if (getCheckFlags(propertySymbol) & CheckFlags.DeferredInferred) {
|
||||
const deferred = propertySymbol as DeferredTransientSymbol;
|
||||
const key = deferred.propertyType.id + "," + (deferred.mappedType.symbol ? deferred.mappedType.symbol.id : "");
|
||||
// Temporary solution to recursive printing: zero out repeated types.
|
||||
if (contains(deferredMappedTypeInstantiationStack, key)) {
|
||||
// TODO: Could probably be an actual cache that returns {} when it contains undefined.
|
||||
propertyType = emptyObjectType;
|
||||
}
|
||||
else {
|
||||
deferredMappedTypeInstantiationStack.push(key)
|
||||
propertyType = getTypeOfSymbol(propertySymbol);
|
||||
}
|
||||
}
|
||||
else {
|
||||
propertyType = getTypeOfSymbol(propertySymbol);
|
||||
}
|
||||
const saveEnclosingDeclaration = context.enclosingDeclaration;
|
||||
context.enclosingDeclaration = undefined;
|
||||
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
|
||||
@ -2894,6 +2911,9 @@ namespace ts {
|
||||
/*initializer*/ undefined);
|
||||
typeElements.push(propertySignature);
|
||||
}
|
||||
if (getCheckFlags(propertySymbol) & CheckFlags.DeferredInferred) {
|
||||
deferredMappedTypeInstantiationStack.pop();
|
||||
}
|
||||
}
|
||||
return typeElements.length ? typeElements : undefined;
|
||||
}
|
||||
@ -4869,7 +4889,7 @@ namespace ts {
|
||||
return getTypeOfInstantiatedSymbol(symbol);
|
||||
}
|
||||
if (getCheckFlags(symbol) & CheckFlags.DeferredInferred) {
|
||||
return inferTargetType((symbol as DeferredTransientSymbol).propertyType, (symbol as DeferredTransientSymbol).mappedType);
|
||||
return inferDeferredMappedType((symbol as DeferredTransientSymbol).propertyType, (symbol as DeferredTransientSymbol).mappedType);
|
||||
}
|
||||
if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
|
||||
return getTypeOfVariableOrParameterOrProperty(symbol);
|
||||
@ -11233,7 +11253,13 @@ namespace ts {
|
||||
if (deferredInferenceCache.has(key)) {
|
||||
return deferredInferenceCache.get(key);
|
||||
}
|
||||
deferredInferenceCache.set(key, function() {
|
||||
deferredInferenceCache.set(key, undefined);
|
||||
const type = createDeferredMappedType(source, target);
|
||||
deferredInferenceCache.set(key, type);
|
||||
return type;
|
||||
}
|
||||
|
||||
function createDeferredMappedType(source: Type, target: MappedType) {
|
||||
const properties = getPropertiesOfType(source);
|
||||
let indexInfo = getIndexInfoOfType(source, IndexKind.String);
|
||||
if (properties.length === 0 && !indexInfo) {
|
||||
@ -11257,14 +11283,15 @@ namespace ts {
|
||||
members.set(prop.escapedName, inferredProp);
|
||||
}
|
||||
if (indexInfo) {
|
||||
// TODO: Defer this too. BARREL OF LAUGHS RIGHT THERE
|
||||
indexInfo = createIndexInfo(inferTargetType(indexInfo.type, target), readonlyMask && indexInfo.isReadonly);
|
||||
// TODO: Defer this too.
|
||||
// (probably the simplest way is to have a special type that defers the creation of (at least) its index info in
|
||||
// resolveStructuredTypeMembers
|
||||
indexInfo = createIndexInfo(inferDeferredMappedType(indexInfo.type, target), readonlyMask && indexInfo.isReadonly);
|
||||
}
|
||||
return createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfo, undefined);
|
||||
}());
|
||||
}
|
||||
|
||||
function inferTargetType(sourceType: Type, target: MappedType): Type {
|
||||
function inferDeferredMappedType(sourceType: Type, target: MappedType): Type {
|
||||
const typeParameter = <TypeParameter>getIndexedAccessType((<IndexType>getConstraintTypeFromMappedType(target)).type, getTypeParameterFromMappedType(target));
|
||||
const templateType = getTemplateTypeFromMappedType(target);
|
||||
const inference = createInferenceInfo(typeParameter);
|
||||
|
||||
@ -3227,6 +3227,7 @@ namespace ts {
|
||||
isRestParameter?: boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface DeferredTransientSymbol extends TransientSymbol {
|
||||
propertyType: Type;
|
||||
mappedType: MappedType;
|
||||
|
||||
@ -26,8 +26,8 @@ declare function foo<T>(deep: Deep<T>): T;
|
||||
>T : T
|
||||
|
||||
const out = foo(a);
|
||||
>out : { a: {}; }
|
||||
>foo(a) : { a: {}; }
|
||||
>out : { a: { a: {}; }; }
|
||||
>foo(a) : { a: { a: {}; }; }
|
||||
>foo : <T>(deep: Deep<T>) => T
|
||||
>a : A
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user