From 61225cc57c1ae9c2aea8ecbd15d24b55e9f3d02f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Dec 2017 09:14:57 -0800 Subject: [PATCH] Introduce TypeFlags.Instatiable --- src/compiler/checker.ts | 43 ++++++++++++++++++++++------------------- src/compiler/types.ts | 9 ++++++--- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2c194ef60b..f643541a329 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6099,7 +6099,7 @@ namespace ts { // First, if the constraint type is a type parameter, obtain the base constraint. Then, // if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X. // Finally, iterate over the constituents of the resulting iteration type. - const keyType = constraintType.flags & TypeFlags.TypeVariable ? getApparentType(constraintType) : constraintType; + const keyType = constraintType.flags & TypeFlags.InstantiableNonPrimitive ? getApparentType(constraintType) : constraintType; const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((keyType).type)) : keyType; forEachType(iterationType, addMemberForKeyType); } @@ -6315,7 +6315,7 @@ namespace ts { } function getBaseConstraintOfType(type: Type): Type { - if (type.flags & (TypeFlags.TypeVariable | TypeFlags.UnionOrIntersection)) { + if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) { const constraint = getResolvedBaseConstraint(type); if (constraint !== noConstraintType && constraint !== circularConstraintType) { return constraint; @@ -6324,6 +6324,9 @@ namespace ts { else if (type.flags & TypeFlags.Index) { return stringType; } + else if (type.flags & TypeFlags.Extends) { + return booleanType; + } return undefined; } @@ -6461,7 +6464,7 @@ namespace ts { * type itself. Note that the apparent type of a union type is the union type itself. */ function getApparentType(type: Type): Type { - const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; + const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || emptyObjectType : type; return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : @@ -8011,10 +8014,10 @@ namespace ts { } function getIndexType(type: Type): Type { - return maybeTypeOfKind(type, TypeFlags.TypeVariable) ? getIndexTypeForGenericType(type) : + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(type) : - type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : - getLiteralTypeFromPropertyNames(type); + type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : + getLiteralTypeFromPropertyNames(type); } function getIndexTypeOrString(type: Type): Type { @@ -8109,11 +8112,11 @@ namespace ts { } function isGenericObjectType(type: Type): boolean { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.GenericMappedType); + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.GenericMappedType); } function isGenericIndexType(type: Type): boolean { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.Index); + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Index); } // Return true if the given type is a non-generic object type with a string index signature and no @@ -8224,7 +8227,7 @@ namespace ts { } function isGenericConditionType(type: Type) { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.Extends); + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Extends); } function createConditionalType(conditionType: Type, whenTrueType: Type, whenFalseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { @@ -8265,7 +8268,7 @@ namespace ts { } function isGenericExtendsType(type: Type) { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.GenericMappedType | TypeFlags.Index | TypeFlags.Extends); + return maybeTypeOfKind(type, TypeFlags.Instantiable | TypeFlags.GenericMappedType); } function createExtendsType(checkType: Type, extendsType: Type) { @@ -9042,7 +9045,7 @@ namespace ts { function isTypeDerivedFrom(source: Type, target: Type): boolean { return source.flags & TypeFlags.Union ? every((source).types, t => isTypeDerivedFrom(t, target)) : target.flags & TypeFlags.Union ? some((target).types, t => isTypeDerivedFrom(source, t)) : - source.flags & TypeFlags.TypeVariable ? isTypeDerivedFrom(getBaseConstraintOfType(source) || emptyObjectType, target) : + source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || emptyObjectType, target) : target === globalObjectType || target === globalFunctionType ? isTypeSubtypeOf(source, target) : hasBaseType(source, getTargetType(target)); } @@ -9379,7 +9382,7 @@ namespace ts { return related === RelationComparisonResult.Succeeded; } } - if (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable) { + if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined); } return false; @@ -9585,7 +9588,7 @@ namespace ts { // breaking the intersection apart. result = someTypeRelatedToType(source, target, /*reportErrors*/ false); } - if (!result && (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable)) { + if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors)) { errorInfo = saveErrorInfo; } @@ -11230,7 +11233,7 @@ namespace ts { // results for union and intersection types for performance reasons. function couldContainTypeVariables(type: Type): boolean { const objectFlags = getObjectFlags(type); - return !!(type.flags & (TypeFlags.TypeVariable | TypeFlags.Index) || + return !!(type.flags & TypeFlags.Instantiable || objectFlags & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeVariables) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || objectFlags & ObjectFlags.Mapped || @@ -12026,7 +12029,7 @@ namespace ts { if (flags & TypeFlags.NonPrimitive) { return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } - if (flags & TypeFlags.TypeVariable) { + if (flags & TypeFlags.Instantiable) { return getTypeFacts(getBaseConstraintOfType(type) || emptyObjectType); } if (flags & TypeFlags.UnionOrIntersection) { @@ -12878,7 +12881,7 @@ namespace ts { if (isTypeSubtypeOf(targetType, type)) { return targetType; } - if (type.flags & TypeFlags.TypeVariable) { + if (type.flags & TypeFlags.Instantiable) { const constraint = getBaseConstraintOfType(type) || anyType; if (isTypeSubtypeOf(targetType, constraint)) { return getIntersectionType([type, targetType]); @@ -13141,7 +13144,7 @@ namespace ts { } function typeHasNullableConstraint(type: Type) { - return type.flags & TypeFlags.TypeVariable && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable); + return type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable); } function getDeclaredOrApparentType(symbol: Symbol, node: Node) { @@ -18535,7 +18538,7 @@ namespace ts { if (!(isTypeComparableTo(leftType, stringType) || isTypeAssignableToKind(leftType, TypeFlags.NumberLike | TypeFlags.ESSymbolLike))) { error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); } - if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.TypeVariable)) { + if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } return booleanType; @@ -19132,7 +19135,7 @@ namespace ts { !(t.flags & TypeFlags.BooleanLiteral && containsType(types, trueType) && containsType(types, falseType)) && isLiteralOfContextualType(candidateType, t)); } - if (contextualType.flags & TypeFlags.TypeVariable) { + if (contextualType.flags & TypeFlags.InstantiableNonPrimitive) { // If the contextual type is a type variable constrained to a primitive type, consider // this a literal context for literals of that primitive type. For example, given a // type parameter 'T extends string', infer string literal types for T. @@ -21878,7 +21881,7 @@ namespace ts { // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.TypeVariable)) { + if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7436701cf64..0f7b8aada5b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3391,12 +3391,15 @@ namespace ts { ESSymbolLike = ESSymbol | UniqueESSymbol, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, - TypeVariable = TypeParameter | IndexedAccess | Conditional, - StructuredOrTypeVariable = StructuredType | TypeVariable | Index | Extends, + TypeVariable = TypeParameter | IndexedAccess, + InstantiableNonPrimitive = TypeVariable | Conditional, + InstantiablePrimitive = Index | Extends, + Instantiable = InstantiableNonPrimitive | InstantiablePrimitive, + StructuredOrInstantiable = StructuredType | Instantiable, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredOrTypeVariable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, + Narrowable = Any | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral,