From 39bb93fb1a94f14235ca9f495c9713dad591393b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 5 Apr 2018 16:00:06 -0700 Subject: [PATCH] Move nameType to base Symbol, generate nameType properties where missing --- src/compiler/checker.ts | 83 ++++++++++++++++++----------------------- src/compiler/types.ts | 10 ++--- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8b692471eba..ff3d53229ba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3793,9 +3793,9 @@ namespace ts { return "(Anonymous function)"; } } - if (isTransientSymbol(symbol)) { - const nameType = (symbol).nameType; - if (nameType && nameType.flags & TypeFlags.StringLiteral && !isIdentifierText((nameType).value, compilerOptions.target)) { + const nameType = symbol.nameType; + if (nameType) { + if (nameType.flags & TypeFlags.StringLiteral && !isIdentifierText((nameType).value, compilerOptions.target)) { return `"${escapeString((nameType).value, CharacterCodes.doubleQuote)}"`; } if (nameType && nameType.flags & TypeFlags.UniqueESSymbol) { @@ -6003,6 +6003,7 @@ namespace ts { const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol; inferredProp.declarations = prop.declarations; + inferredProp.nameType = prop.nameType; inferredProp.propertyType = getTypeOfSymbol(prop); inferredProp.mappedType = type.mappedType; members.set(prop.escapedName, inferredProp); @@ -6027,8 +6028,8 @@ namespace ts { if (constraintDeclaration.kind === SyntaxKind.TypeOperator && (constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) { // We have a { [P in keyof T]: X } - for (const propertySymbol of getPropertiesOfType(modifiersType)) { - addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol); + for (const prop of getPropertiesOfType(modifiersType)) { + addMemberForKeyType(getLiteralTypeFromPropertyName(prop), undefined, prop); } if (modifiersType.flags & TypeFlags.Any || getIndexInfoOfType(modifiersType, IndexKind.String)) { addMemberForKeyType(stringType); @@ -6044,14 +6045,7 @@ namespace ts { } setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); - function addMemberForKeyType(t: Type, propertySymbolOrIndex?: Symbol | number) { - let propertySymbol: Symbol; - // forEachType delegates to forEach, which calls with a numeric second argument - // the type system currently doesn't catch this incompatibility, so we annotate - // the function ourselves to indicate the runtime behavior and deal with it here - if (typeof propertySymbolOrIndex === "object") { - propertySymbol = propertySymbolOrIndex; - } + function addMemberForKeyType(t: Type, _index?: number, origin?: Symbol) { // Create a mapper from T to the current iteration type constituent. Then, if the // mapped type is itself an instantiated type, combine the iteration mapper with the // instantiation mapper. @@ -6060,7 +6054,7 @@ namespace ts { // If the current iteration type constituent is a string literal type, create a property. // Otherwise, for type string create a string index signature. if (t.flags & TypeFlags.StringLiteral) { - const propName = getLateBoundNameFromType(t as LiteralType | UniqueESSymbolType); + const propName = getLateBoundNameFromType(t as LiteralType); const modifiersProp = getPropertyOfType(modifiersType, propName); const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional || !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional); @@ -6073,9 +6067,9 @@ namespace ts { prop.type = strictNullChecks && isOptional && !isTypeAssignableTo(undefinedType, propType) ? getOptionalType(propType) : strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : propType; - if (propertySymbol) { - prop.syntheticOrigin = propertySymbol; - prop.declarations = propertySymbol.declarations; + if (origin) { + prop.syntheticOrigin = origin; + prop.declarations = origin.declarations; } prop.nameType = t; members.set(propName, prop); @@ -6529,6 +6523,7 @@ namespace ts { } propTypes.push(type); } + // !!! const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags); result.containingType = containingType; result.declarations = declarations; @@ -8116,11 +8111,7 @@ namespace ts { if (getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier || isKnownSymbol(prop)) { return neverType; } - const symbol = getLateBoundSymbol(prop); - if (isTransientSymbol(symbol) && symbol.nameType) { - return symbol.nameType; - } - return getLiteralType(symbolName(prop)); + return getLateBoundSymbol(prop).nameType || getLiteralType(symbolName(prop)); } function getLiteralTypeFromPropertyNames(type: Type) { @@ -8681,6 +8672,7 @@ namespace ts { result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; + result.nameType = leftProp.nameType; members.set(leftProp.escapedName, result); } } @@ -8709,6 +8701,7 @@ namespace ts { const result = createSymbol(flags, prop.escapedName); result.type = getTypeOfSymbol(prop); result.declarations = prop.declarations; + result.nameType = prop.nameType; result.syntheticOrigin = prop; return result; } @@ -9054,13 +9047,13 @@ namespace ts { if (symbol.valueDeclaration) { result.valueDeclaration = symbol.valueDeclaration; } + if (symbol.nameType) { + result.nameType = symbol.nameType; + } if (isTransientSymbol(symbol)) { if (symbol.isRestParameter) { result.isRestParameter = symbol.isRestParameter; } - if (symbol.nameType) { - result.nameType = symbol.nameType; - } } return result; } @@ -10772,8 +10765,7 @@ namespace ts { continue; } // Skip over symbol-named members - const nameType = getLiteralTypeFromPropertyName(prop); - if (nameType !== undefined && !(isRelatedTo(nameType, stringType) || isRelatedTo(nameType, numberType))) { + if (prop.nameType && prop.nameType.flags & TypeFlags.UniqueESSymbol) { continue; } if (kind === IndexKind.String || isNumericLiteralName(prop.escapedName)) { @@ -11376,6 +11368,9 @@ namespace ts { if (source.valueDeclaration) { symbol.valueDeclaration = source.valueDeclaration; } + if (source.nameType) { + symbol.nameType = source.nameType; + } return symbol; } @@ -11418,7 +11413,7 @@ namespace ts { } function createWideningContext(parent: WideningContext, propertyName: __String, siblings: Type[]): WideningContext { - return { parent, propertyName, siblings, resolvedPropertyNames: undefined }; + return { parent, propertyName, siblings, resolvedProperties: undefined }; } function getSiblingsOfContext(context: WideningContext): Type[] { @@ -11439,19 +11434,19 @@ namespace ts { return context.siblings; } - function getPropertyNamesOfContext(context: WideningContext): __String[] { - if (!context.resolvedPropertyNames) { - const names = createMap() as UnderscoreEscapedMap; + function getPropertiesOfContext(context: WideningContext): Symbol[] { + if (!context.resolvedProperties) { + const names = createMap() as UnderscoreEscapedMap; for (const t of getSiblingsOfContext(context)) { if (isObjectLiteralType(t) && !(getObjectFlags(t) & ObjectFlags.ContainsSpread)) { for (const prop of getPropertiesOfType(t)) { - names.set(prop.escapedName, true); + names.set(prop.escapedName, prop); } } } - context.resolvedPropertyNames = arrayFrom(names.keys()); + context.resolvedProperties = arrayFrom(names.values()); } - return context.resolvedPropertyNames; + return context.resolvedProperties; } function getWidenedProperty(prop: Symbol, context: WideningContext): Symbol { @@ -11461,18 +11456,14 @@ namespace ts { return widened === original ? prop : createSymbolWithType(prop, widened); } - function getUndefinedProperty(name: __String) { - const cached = undefinedProperties.get(name); + function getUndefinedProperty(prop: Symbol) { + const cached = undefinedProperties.get(prop.escapedName); if (cached) { return cached; } - const result = createSymbol(SymbolFlags.Property | SymbolFlags.Optional, name); - result.type = undefinedType; - const associatedKeyType = getLiteralType(unescapeLeadingUnderscores(name)); - if (associatedKeyType.flags & TypeFlags.StringLiteral) { - result.nameType = associatedKeyType; - } - undefinedProperties.set(name, result); + const result = createSymbolWithType(prop, undefinedType); + result.flags |= SymbolFlags.Optional; + undefinedProperties.set(prop.escapedName, result); return result; } @@ -11484,9 +11475,9 @@ namespace ts { members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop); } if (context) { - for (const name of getPropertyNamesOfContext(context)) { - if (!members.has(name)) { - members.set(name, getUndefinedProperty(name)); + for (const prop of getPropertiesOfContext(context)) { + if (!members.has(prop.escapedName)) { + members.set(prop.escapedName, getUndefinedProperty(prop)); } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 768cb196cca..bd526921c2a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3361,6 +3361,7 @@ namespace ts { members?: SymbolTable; // Class, interface or object literal instance members exports?: SymbolTable; // Module exports globalExports?: SymbolTable; // Conditional global UMD exports + nameType?: Type; // Type associated with a late-bound symbol /* @internal */ id?: number; // Unique id (used to look up SymbolLinks) /* @internal */ mergeId?: number; // Merge id (used to look up merged symbol) /* @internal */ parent?: Symbol; // Parent symbol @@ -3428,7 +3429,6 @@ namespace ts { export interface TransientSymbol extends Symbol, SymbolLinks { checkFlags: CheckFlags; isRestParameter?: boolean; - nameType?: Type; // Type associated with a late-bound symbol } /* @internal */ @@ -4029,10 +4029,10 @@ namespace ts { /* @internal */ export interface WideningContext { - parent?: WideningContext; // Parent context - propertyName?: __String; // Name of property in parent - siblings?: Type[]; // Types of siblings - resolvedPropertyNames?: __String[]; // Property names occurring in sibling object literals + parent?: WideningContext; // Parent context + propertyName?: __String; // Name of property in parent + siblings?: Type[]; // Types of siblings + resolvedProperties?: Symbol[]; // Properties occurring in sibling object literals } /* @internal */