From 8c70109d1855f9e60217f4a2068f07ba87474c6b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 28 Sep 2016 09:52:08 -0700 Subject: [PATCH 1/8] Turn 3 type flags into properties 1. Instantiated (only modifies anonymous types) 2. ObjectLiteralWithComputedProperties (only modifies [resolved] object types) 3. ThisType (only modifies type parameters) This is needed for object spread and rest, which will each need a type flag. There are 4-5 other likely targets for removal, and I may remove those later. --- src/compiler/checker.ts | 44 +++++++++++++++++++++-------------------- src/compiler/types.ts | 20 ++++++++++--------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 61cf701eb95..e7fd07045ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2164,7 +2164,7 @@ namespace ts { ? "any" : (type).intrinsicName); } - else if (type.flags & TypeFlags.ThisType) { + else if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (inObjectTypeLiteral) { writer.reportInaccessibleThisError(); } @@ -3155,9 +3155,9 @@ namespace ts { } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): ResolvedType { const members = createMap(); - let hasComputedProperties = false; + let hasComputedProperties: boolean; forEach(pattern.elements, e => { const name = e.propertyName || e.name; if (isComputedNonLiteralName(name)) { @@ -3177,9 +3177,7 @@ namespace ts { if (includePatternInType) { result.pattern = pattern; } - if (hasComputedProperties) { - result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties; - } + result.inObjectLiteralPatternWithComputedProperties = hasComputedProperties; return result; } @@ -3765,7 +3763,8 @@ namespace ts { (type).instantiations[getTypeListId(type.typeParameters)] = type; (type).target = type; (type).typeArguments = type.typeParameters; - type.thisType = createType(TypeFlags.TypeParameter | TypeFlags.ThisType); + type.thisType = createType(TypeFlags.TypeParameter); + type.thisType.isThisType = true; type.thisType.symbol = symbol; type.thisType.constraint = type; } @@ -4414,7 +4413,7 @@ namespace ts { * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the * type itself. Note that the apparent type of a union type is the union type itself. */ - function getApparentType(type: Type): Type { + function getApparentType(type: Type): ObjectType { if (type.flags & TypeFlags.TypeParameter) { type = getApparentTypeOfTypeParameter(type); } @@ -4967,7 +4966,7 @@ namespace ts { function hasConstraintReferenceTo(type: Type, target: TypeParameter): boolean { let checked: Type[]; - while (type && !(type.flags & TypeFlags.ThisType) && type.flags & TypeFlags.TypeParameter && !contains(checked, type)) { + while (type && type.flags & TypeFlags.TypeParameter && !((type as TypeParameter).isThisType) && !contains(checked, type)) { if (type === target) { return true; } @@ -5330,7 +5329,8 @@ namespace ts { type.instantiations[getTypeListId(type.typeParameters)] = type; type.target = type; type.typeArguments = type.typeParameters; - type.thisType = createType(TypeFlags.TypeParameter | TypeFlags.ThisType); + type.thisType = createType(TypeFlags.TypeParameter); + type.thisType.isThisType = true; type.thisType.constraint = type; type.declaredProperties = properties; type.declaredCallSignatures = emptyArray; @@ -5920,7 +5920,8 @@ namespace ts { mapper.instantiations = []; } // Mark the anonymous type as instantiated such that our infinite instantiation detection logic can recognize it - const result = createObjectType(TypeFlags.Anonymous | TypeFlags.Instantiated, type.symbol); + const result = createObjectType(TypeFlags.Anonymous, type.symbol); + result.isInstantiated = true; result.target = type; result.mapper = mapper; result.aliasSymbol = type.aliasSymbol; @@ -5992,7 +5993,7 @@ namespace ts { // instantiation. return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && - (type.flags & TypeFlags.Instantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ? + ((type as AnonymousType).isInstantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ? instantiateAnonymousType(type, mapper) : type; } if (type.flags & TypeFlags.Reference) { @@ -6646,7 +6647,7 @@ namespace ts { } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && maybeTypeOfKind(target, TypeFlags.ObjectType)) { + if (maybeTypeOfKind(target, TypeFlags.ObjectType) && !(target as ObjectType).inObjectLiteralPatternWithComputedProperties) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { @@ -7140,12 +7141,12 @@ namespace ts { // some level beyond that. function isDeeplyNestedGeneric(type: Type, stack: Type[], depth: number): boolean { // We track type references (created by createTypeReference) and instantiated types (created by instantiateType) - if (type.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && depth >= 5) { + if ((type.flags & TypeFlags.Reference || type.flags & TypeFlags.Anonymous && (type as AnonymousType).isInstantiated) && depth >= 5) { const symbol = type.symbol; let count = 0; for (let i = 0; i < depth; i++) { const t = stack[i]; - if (t.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && t.symbol === symbol) { + if ((t.flags & TypeFlags.Reference || t.flags & TypeFlags.Anonymous && (t as AnonymousType).isInstantiated) && t.symbol === symbol) { count++; if (count >= 5) return true; } @@ -9937,7 +9938,7 @@ namespace ts { // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. - function getApparentTypeOfContextualType(node: Expression): Type { + function getApparentTypeOfContextualType(node: Expression): ObjectType { const type = getContextualType(node); return type && getApparentType(type); } @@ -10271,7 +10272,7 @@ namespace ts { const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); let typeFlags: TypeFlags = 0; - let patternWithComputedProperties = false; + let patternWithComputedProperties: boolean | undefined; let hasComputedStringProperty = false; let hasComputedNumberProperty = false; @@ -10306,7 +10307,7 @@ namespace ts { patternWithComputedProperties = true; } } - else if (contextualTypeHasPattern && !(contextualType.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties)) { + else if (contextualTypeHasPattern && !contextualType.inObjectLiteralPatternWithComputedProperties) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.name); @@ -10371,7 +10372,8 @@ namespace ts { const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral; - result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0); + result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); + result.inObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; if (inDestructuringPattern) { result.pattern = node; } @@ -10941,7 +10943,7 @@ namespace ts { return true; } // An instance property must be accessed through an instance of the enclosing class - if (type.flags & TypeFlags.ThisType) { + if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { // get the original type -- represented as the type constraint of the 'this' type type = getConstraintOfTypeParameter(type); } @@ -10991,7 +10993,7 @@ namespace ts { const prop = getPropertyOfType(apparentType, right.text); if (!prop) { if (right.text && !checkAndReportErrorForExtendingInterface(node)) { - reportNonexistentProperty(right, type.flags & TypeFlags.ThisType ? apparentType : type); + reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type); } return unknownType; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ab48ae543c2..a9529659b3e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2382,19 +2382,16 @@ namespace ts { Union = 1 << 19, // Union (T | U) Intersection = 1 << 20, // Intersection (T & U) Anonymous = 1 << 21, // Anonymous - Instantiated = 1 << 22, // Instantiated anonymous type /* @internal */ - ObjectLiteral = 1 << 23, // Originates in an object literal + ObjectLiteral = 1 << 22, // Originates in an object literal /* @internal */ - FreshLiteral = 1 << 24, // Fresh literal type + FreshLiteral = 1 << 23, // Fresh literal type /* @internal */ - ContainsWideningType = 1 << 25, // Type is or contains undefined or null widening type + ContainsWideningType = 1 << 24, // Type is or contains undefined or null widening type /* @internal */ - ContainsObjectLiteral = 1 << 26, // Type is or contains object literal type + ContainsObjectLiteral = 1 << 25, // Type is or contains object literal type /* @internal */ - ContainsAnyFunctionType = 1 << 27, // Type is or contains object literal type - ThisType = 1 << 28, // This type - ObjectLiteralPatternWithComputedProperties = 1 << 29, // Object literal type implied by binding pattern has computed properties + ContainsAnyFunctionType = 1 << 26, // Type is or contains object literal type /* @internal */ Nullable = Undefined | Null, @@ -2463,7 +2460,9 @@ namespace ts { } // Object types (TypeFlags.ObjectType) - export interface ObjectType extends Type { } + export interface ObjectType extends Type { + inObjectLiteralPatternWithComputedProperties?: boolean; + } // Class and interface types (TypeFlags.Class and TypeFlags.Interface) export interface InterfaceType extends ObjectType { @@ -2519,6 +2518,7 @@ namespace ts { /* @internal */ // An instantiated anonymous type has a target and a mapper export interface AnonymousType extends ObjectType { + isInstantiated?: boolean; target?: AnonymousType; // Instantiation target mapper?: TypeMapper; // Instantiation mapper } @@ -2558,6 +2558,8 @@ namespace ts { mapper?: TypeMapper; // Instantiation mapper /* @internal */ resolvedApparentType: Type; + /* @internal */ + isThisType?: boolean; } export const enum SignatureKind { From bc028a3cf0664e145031960f16043fb797dbd9b4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 29 Sep 2016 10:30:41 -0700 Subject: [PATCH 2/8] Remove TypeFlags.ObjectLiteral, not Instantiated --- src/compiler/checker.ts | 55 ++++++++++++++++++++++++----------------- src/compiler/types.ts | 13 +++++----- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e7fd07045ec..5c38b9477ed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1618,9 +1618,12 @@ namespace ts { return type; } - function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType { - return setObjectTypeMembers(createObjectType(TypeFlags.Anonymous, symbol), - members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo, isObjectLiteral?: boolean): ResolvedType { + const t = createObjectType(TypeFlags.Anonymous, symbol); + if (isObjectLiteral) { + t.isObjectLiteral = true; + } + return setObjectTypeMembers(t, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); } function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T { @@ -3177,7 +3180,9 @@ namespace ts { if (includePatternInType) { result.pattern = pattern; } - result.inObjectLiteralPatternWithComputedProperties = hasComputedProperties; + if (hasComputedProperties) { + result.inObjectLiteralPatternWithComputedProperties = hasComputedProperties; + } return result; } @@ -4413,7 +4418,7 @@ namespace ts { * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the * type itself. Note that the apparent type of a union type is the union type itself. */ - function getApparentType(type: Type): ObjectType { + function getApparentType(type: Type): Type { if (type.flags & TypeFlags.TypeParameter) { type = getApparentTypeOfTypeParameter(type); } @@ -5920,8 +5925,7 @@ namespace ts { mapper.instantiations = []; } // Mark the anonymous type as instantiated such that our infinite instantiation detection logic can recognize it - const result = createObjectType(TypeFlags.Anonymous, type.symbol); - result.isInstantiated = true; + const result = createObjectType(TypeFlags.Anonymous | TypeFlags.Instantiated, type.symbol); result.target = type; result.mapper = mapper; result.aliasSymbol = type.aliasSymbol; @@ -5993,7 +5997,7 @@ namespace ts { // instantiation. return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && - ((type as AnonymousType).isInstantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ? + (type.flags & TypeFlags.Instantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ? instantiateAnonymousType(type, mapper) : type; } if (type.flags & TypeFlags.Reference) { @@ -6473,7 +6477,7 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; - if (source.flags & TypeFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) { + if (source.flags & TypeFlags.ObjectType && (source as ObjectType).isObjectLiteral && source.flags & TypeFlags.FreshLiteral) { if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { reportRelationError(headMessage, source, target); @@ -6647,7 +6651,8 @@ namespace ts { } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (maybeTypeOfKind(target, TypeFlags.ObjectType) && !(target as ObjectType).inObjectLiteralPatternWithComputedProperties) { + if (maybeTypeOfKind(target, TypeFlags.ObjectType) && + (!(target.flags & TypeFlags.ObjectType) || !(target as ObjectType).inObjectLiteralPatternWithComputedProperties)) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { @@ -6841,7 +6846,7 @@ namespace ts { } let result = Ternary.True; const properties = getPropertiesOfObjectType(target); - const requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectLiteral); + const requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectType && (source as ObjectType).isObjectLiteral); for (const targetProp of properties) { const sourceProp = getPropertyOfType(source, targetProp.name); @@ -7141,12 +7146,12 @@ namespace ts { // some level beyond that. function isDeeplyNestedGeneric(type: Type, stack: Type[], depth: number): boolean { // We track type references (created by createTypeReference) and instantiated types (created by instantiateType) - if ((type.flags & TypeFlags.Reference || type.flags & TypeFlags.Anonymous && (type as AnonymousType).isInstantiated) && depth >= 5) { + if (type.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && depth >= 5) { const symbol = type.symbol; let count = 0; for (let i = 0; i < depth; i++) { const t = stack[i]; - if ((t.flags & TypeFlags.Reference || t.flags & TypeFlags.Anonymous && (t as AnonymousType).isInstantiated) && t.symbol === symbol) { + if (t.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && t.symbol === symbol) { count++; if (count >= 5) return true; } @@ -7480,7 +7485,7 @@ namespace ts { * Leave signatures alone since they are not subject to the check. */ function getRegularTypeOfObjectLiteral(type: Type): Type { - if (!(type.flags & TypeFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral)) { + if (!(type.flags & TypeFlags.ObjectType && (type as ObjectType).isObjectLiteral && type.flags & TypeFlags.FreshLiteral)) { return type; } const regularType = (type).regularType; @@ -7495,7 +7500,8 @@ namespace ts { resolved.callSignatures, resolved.constructSignatures, resolved.stringIndexInfo, - resolved.numberIndexInfo); + resolved.numberIndexInfo, + resolved.isObjectLiteral); regularNew.flags = resolved.flags & ~TypeFlags.FreshLiteral; (type).regularType = regularNew; return regularNew; @@ -7510,7 +7516,8 @@ namespace ts { const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number); return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexInfo && createIndexInfo(getWidenedType(stringIndexInfo.type), stringIndexInfo.isReadonly), - numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly)); + numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly), + (type as ObjectType).isObjectLiteral); } function getWidenedConstituentType(type: Type): Type { @@ -7522,7 +7529,8 @@ namespace ts { if (type.flags & TypeFlags.Nullable) { return anyType; } - if (type.flags & TypeFlags.ObjectLiteral) { + // if (type.flags & TypeFlags.ObjectLiteral) { + if (type.flags & TypeFlags.ObjectType && (type as ObjectType).isObjectLiteral) { return getWidenedTypeOfObjectLiteral(type); } if (type.flags & TypeFlags.Union) { @@ -7562,7 +7570,7 @@ namespace ts { } } } - if (type.flags & TypeFlags.ObjectLiteral) { + if (type.flags & TypeFlags.ObjectType && (type as ObjectType).isObjectLiteral) { for (const p of getPropertiesOfObjectType(type)) { const t = getTypeOfSymbol(p); if (t.flags & TypeFlags.ContainsWideningType) { @@ -9938,7 +9946,7 @@ namespace ts { // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. - function getApparentTypeOfContextualType(node: Expression): ObjectType { + function getApparentTypeOfContextualType(node: Expression): Type { const type = getContextualType(node); return type && getApparentType(type); } @@ -10307,7 +10315,8 @@ namespace ts { patternWithComputedProperties = true; } } - else if (contextualTypeHasPattern && !contextualType.inObjectLiteralPatternWithComputedProperties) { + else if (contextualTypeHasPattern && + !(contextualType.flags & TypeFlags.ObjectType && (contextualType as ObjectType).inObjectLiteralPatternWithComputedProperties)) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.name); @@ -10370,10 +10379,12 @@ namespace ts { const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined; const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; - const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo, /*isObjectLiteral*/ true); const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral; result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); - result.inObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; + if (patternWithComputedProperties) { + result.inObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; + } if (inDestructuringPattern) { result.pattern = node; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a9529659b3e..7b4f8dced69 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2382,16 +2382,17 @@ namespace ts { Union = 1 << 19, // Union (T | U) Intersection = 1 << 20, // Intersection (T & U) Anonymous = 1 << 21, // Anonymous + Instantiated = 1 << 22, // Instantiated anonymous type /* @internal */ - ObjectLiteral = 1 << 22, // Originates in an object literal + ObjectLiteral = 1 << 23, // Originates in an object literal /* @internal */ - FreshLiteral = 1 << 23, // Fresh literal type + FreshLiteral = 1 << 24, // Fresh literal type /* @internal */ - ContainsWideningType = 1 << 24, // Type is or contains undefined or null widening type + ContainsWideningType = 1 << 25, // Type is or contains undefined or null widening type /* @internal */ - ContainsObjectLiteral = 1 << 25, // Type is or contains object literal type + ContainsObjectLiteral = 1 << 26, // Type is or contains object literal type /* @internal */ - ContainsAnyFunctionType = 1 << 26, // Type is or contains object literal type + ContainsAnyFunctionType = 1 << 27, // Type is or contains object literal type /* @internal */ Nullable = Undefined | Null, @@ -2461,6 +2462,7 @@ namespace ts { // Object types (TypeFlags.ObjectType) export interface ObjectType extends Type { + isObjectLiteral?: boolean; inObjectLiteralPatternWithComputedProperties?: boolean; } @@ -2518,7 +2520,6 @@ namespace ts { /* @internal */ // An instantiated anonymous type has a target and a mapper export interface AnonymousType extends ObjectType { - isInstantiated?: boolean; target?: AnonymousType; // Instantiation target mapper?: TypeMapper; // Instantiation mapper } From 561168c01cdc3b43edb0a5394ba0b3bc55980e5f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 29 Sep 2016 10:46:54 -0700 Subject: [PATCH 3/8] Make isObjectLiteral required --- src/compiler/checker.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5c38b9477ed..3c73bccb049 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -134,16 +134,16 @@ namespace ts { const neverType = createIntrinsicType(TypeFlags.Never, "never"); const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); - const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); + const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); emptyGenericType.instantiations = createMap(); - const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); // The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated // in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes. anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType; - const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); @@ -1618,7 +1618,7 @@ namespace ts { return type; } - function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo, isObjectLiteral?: boolean): ResolvedType { + function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo, isObjectLiteral: boolean): ResolvedType { const t = createObjectType(TypeFlags.Anonymous, symbol); if (isObjectLiteral) { t.isObjectLiteral = true; @@ -3176,7 +3176,7 @@ namespace ts { symbol.bindingElement = e; members[symbol.name] = symbol; }); - const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); + const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined, undefined); if (includePatternInType) { result.pattern = pattern; } @@ -12492,7 +12492,7 @@ namespace ts { function getInferredClassType(symbol: Symbol) { const links = getSymbolLinks(symbol); if (!links.inferredClassType) { - links.inferredClassType = createAnonymousType(symbol, symbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); + links.inferredClassType = createAnonymousType(symbol, symbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined, /*isObjectLiteral*/ undefined); } return links.inferredClassType; } From 9e1b5300c4693091783b2d82fe44aeb1e5f021b8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 29 Sep 2016 11:26:58 -0700 Subject: [PATCH 4/8] Put TypeFlags.ObjectLiteral back --- src/compiler/checker.ts | 40 +++++++++++++++++----------------------- src/compiler/types.ts | 1 - 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3c73bccb049..7a2ec512e5a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -134,16 +134,16 @@ namespace ts { const neverType = createIntrinsicType(TypeFlags.Never, "never"); const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); - const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); - const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); + const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); emptyGenericType.instantiations = createMap(); - const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); + const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); // The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated // in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes. anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType; - const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); + const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); @@ -1618,12 +1618,9 @@ namespace ts { return type; } - function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo, isObjectLiteral: boolean): ResolvedType { - const t = createObjectType(TypeFlags.Anonymous, symbol); - if (isObjectLiteral) { - t.isObjectLiteral = true; - } - return setObjectTypeMembers(t, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType { + return setObjectTypeMembers(createObjectType(TypeFlags.Anonymous, symbol), + members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); } function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T { @@ -3176,7 +3173,7 @@ namespace ts { symbol.bindingElement = e; members[symbol.name] = symbol; }); - const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined, undefined); + const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); if (includePatternInType) { result.pattern = pattern; } @@ -6477,7 +6474,7 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; - if (source.flags & TypeFlags.ObjectType && (source as ObjectType).isObjectLiteral && source.flags & TypeFlags.FreshLiteral) { + if (source.flags & TypeFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) { if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { reportRelationError(headMessage, source, target); @@ -6846,7 +6843,7 @@ namespace ts { } let result = Ternary.True; const properties = getPropertiesOfObjectType(target); - const requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectType && (source as ObjectType).isObjectLiteral); + const requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectLiteral); for (const targetProp of properties) { const sourceProp = getPropertyOfType(source, targetProp.name); @@ -7485,7 +7482,7 @@ namespace ts { * Leave signatures alone since they are not subject to the check. */ function getRegularTypeOfObjectLiteral(type: Type): Type { - if (!(type.flags & TypeFlags.ObjectType && (type as ObjectType).isObjectLiteral && type.flags & TypeFlags.FreshLiteral)) { + if (!(type.flags & TypeFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral)) { return type; } const regularType = (type).regularType; @@ -7500,8 +7497,7 @@ namespace ts { resolved.callSignatures, resolved.constructSignatures, resolved.stringIndexInfo, - resolved.numberIndexInfo, - resolved.isObjectLiteral); + resolved.numberIndexInfo); regularNew.flags = resolved.flags & ~TypeFlags.FreshLiteral; (type).regularType = regularNew; return regularNew; @@ -7516,8 +7512,7 @@ namespace ts { const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number); return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexInfo && createIndexInfo(getWidenedType(stringIndexInfo.type), stringIndexInfo.isReadonly), - numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly), - (type as ObjectType).isObjectLiteral); + numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly)); } function getWidenedConstituentType(type: Type): Type { @@ -7529,8 +7524,7 @@ namespace ts { if (type.flags & TypeFlags.Nullable) { return anyType; } - // if (type.flags & TypeFlags.ObjectLiteral) { - if (type.flags & TypeFlags.ObjectType && (type as ObjectType).isObjectLiteral) { + if (type.flags & TypeFlags.ObjectLiteral) { return getWidenedTypeOfObjectLiteral(type); } if (type.flags & TypeFlags.Union) { @@ -7570,7 +7564,7 @@ namespace ts { } } } - if (type.flags & TypeFlags.ObjectType && (type as ObjectType).isObjectLiteral) { + if (type.flags & TypeFlags.ObjectLiteral) { for (const p of getPropertiesOfObjectType(type)) { const t = getTypeOfSymbol(p); if (t.flags & TypeFlags.ContainsWideningType) { @@ -10379,7 +10373,7 @@ namespace ts { const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined; const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; - const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo, /*isObjectLiteral*/ true); + const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral; result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); if (patternWithComputedProperties) { @@ -12492,7 +12486,7 @@ namespace ts { function getInferredClassType(symbol: Symbol) { const links = getSymbolLinks(symbol); if (!links.inferredClassType) { - links.inferredClassType = createAnonymousType(symbol, symbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined, /*isObjectLiteral*/ undefined); + links.inferredClassType = createAnonymousType(symbol, symbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); } return links.inferredClassType; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7b4f8dced69..d5afd486d65 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2462,7 +2462,6 @@ namespace ts { // Object types (TypeFlags.ObjectType) export interface ObjectType extends Type { - isObjectLiteral?: boolean; inObjectLiteralPatternWithComputedProperties?: boolean; } From 84e319e226670a571b07f19368fcf5c5ac564cf2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 3 Oct 2016 15:54:41 -0700 Subject: [PATCH 5/8] Minor style cleanup --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7a2ec512e5a..07a81967661 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3157,7 +3157,7 @@ namespace ts { // Return the type implied by an object binding pattern function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): ResolvedType { const members = createMap(); - let hasComputedProperties: boolean; + let hasComputedProperties = false; forEach(pattern.elements, e => { const name = e.propertyName || e.name; if (isComputedNonLiteralName(name)) { @@ -10274,7 +10274,7 @@ namespace ts { const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); let typeFlags: TypeFlags = 0; - let patternWithComputedProperties: boolean | undefined; + let patternWithComputedProperties = false; let hasComputedStringProperty = false; let hasComputedNumberProperty = false; From 663ee44e62ecb885453db36dec542a335a449488 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 3 Oct 2016 16:01:08 -0700 Subject: [PATCH 6/8] Rename isObjectLiteralPatternWithComputedProperties --- src/compiler/checker.ts | 8 ++++---- src/compiler/types.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 34a850ea152..e7b9b011fbc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3179,7 +3179,7 @@ namespace ts { result.pattern = pattern; } if (hasComputedProperties) { - result.inObjectLiteralPatternWithComputedProperties = hasComputedProperties; + result.isObjectLiteralPatternWithComputedProperties = hasComputedProperties; } return result; } @@ -6650,7 +6650,7 @@ namespace ts { function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { if (maybeTypeOfKind(target, TypeFlags.ObjectType) && - (!(target.flags & TypeFlags.ObjectType) || !(target as ObjectType).inObjectLiteralPatternWithComputedProperties)) { + (!(target.flags & TypeFlags.ObjectType) || !(target as ObjectType).isObjectLiteralPatternWithComputedProperties)) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { @@ -10311,7 +10311,7 @@ namespace ts { } } else if (contextualTypeHasPattern && - !(contextualType.flags & TypeFlags.ObjectType && (contextualType as ObjectType).inObjectLiteralPatternWithComputedProperties)) { + !(contextualType.flags & TypeFlags.ObjectType && (contextualType as ObjectType).isObjectLiteralPatternWithComputedProperties)) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.name); @@ -10378,7 +10378,7 @@ namespace ts { const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral; result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); if (patternWithComputedProperties) { - result.inObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; + result.isObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; } if (inDestructuringPattern) { result.pattern = node; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0f7eb00131b..4a4a25fd627 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2462,7 +2462,7 @@ namespace ts { // Object types (TypeFlags.ObjectType) export interface ObjectType extends Type { - inObjectLiteralPatternWithComputedProperties?: boolean; + isObjectLiteralPatternWithComputedProperties?: boolean; } // Class and interface types (TypeFlags.Class and TypeFlags.Interface) From 45af47a12fab2264a2ed4a0f71e90141d0782eaf Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 3 Oct 2016 16:06:06 -0700 Subject: [PATCH 7/8] getTypeFromObjectBindingPattern just returns Type again --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e7b9b011fbc..a9e46bf1188 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3156,7 +3156,7 @@ namespace ts { } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): ResolvedType { + function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const members = createMap(); let hasComputedProperties = false; forEach(pattern.elements, e => { From f8526960873a5000347f73c536e663de3e651a6d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 3 Oct 2016 16:10:16 -0700 Subject: [PATCH 8/8] Just assign true inside an if where a boolean was just checked --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a9e46bf1188..422f2a70dcc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3179,7 +3179,7 @@ namespace ts { result.pattern = pattern; } if (hasComputedProperties) { - result.isObjectLiteralPatternWithComputedProperties = hasComputedProperties; + result.isObjectLiteralPatternWithComputedProperties = true; } return result; } @@ -10378,7 +10378,7 @@ namespace ts { const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral; result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); if (patternWithComputedProperties) { - result.isObjectLiteralPatternWithComputedProperties = patternWithComputedProperties; + result.isObjectLiteralPatternWithComputedProperties = true; } if (inDestructuringPattern) { result.pattern = node;