@@ -108,15 +108,21 @@ namespace ts {
108108 isOptionalParameter
109109 };
110110
111+ const tupleTypes: Map<TupleType> = {};
112+ const unionTypes: Map<UnionType> = {};
113+ const intersectionTypes: Map<IntersectionType> = {};
114+ const stringLiteralTypes: Map<LiteralType> = {};
115+ const numericLiteralTypes: Map<LiteralType> = {};
116+
111117 const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
112118 const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
113119
114120 const anyType = createIntrinsicType(TypeFlags.Any, "any");
115121 const stringType = createIntrinsicType(TypeFlags.String, "string");
116122 const numberType = createIntrinsicType(TypeFlags.Number, "number");
117- const booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean");
118123 const trueType = createIntrinsicType(TypeFlags.BooleanLiteral, "true");
119124 const falseType = createIntrinsicType(TypeFlags.BooleanLiteral, "false");
125+ const booleanType = createBooleanType([trueType, falseType]);
120126 const esSymbolType = createIntrinsicType(TypeFlags.ESSymbol, "symbol");
121127 const voidType = createIntrinsicType(TypeFlags.Void, "void");
122128 const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
@@ -196,14 +202,8 @@ namespace ts {
196202 let flowLoopCount = 0;
197203 let visitedFlowCount = 0;
198204
199- const tupleTypes: Map<TupleType> = {};
200- const unionTypes: Map<UnionType> = {};
201- const intersectionTypes: Map<IntersectionType> = {};
202- const stringLiteralTypes: Map<LiteralType> = {};
203- const numericLiteralTypes: Map<LiteralType> = {};
204205 const emptyStringType = getLiteralTypeForText(TypeFlags.StringLiteral, "");
205206 const zeroType = getLiteralTypeForText(TypeFlags.NumberLiteral, "0");
206- const trueFalseType = getUnionType([trueType, falseType]);
207207
208208 const resolutionTargets: TypeSystemEntity[] = [];
209209 const resolutionResults: boolean[] = [];
@@ -1547,6 +1547,13 @@ namespace ts {
15471547 return type;
15481548 }
15491549
1550+ function createBooleanType(trueFalseTypes: Type[]): IntrinsicType {
1551+ const type = <IntrinsicType>getUnionType(trueFalseTypes, /*noSubtypeReduction*/ true);
1552+ type.flags |= TypeFlags.Boolean;
1553+ type.intrinsicName = "boolean";
1554+ return type;
1555+ }
1556+
15501557 function createObjectType(kind: TypeFlags, symbol?: Symbol): ObjectType {
15511558 const type = <ObjectType>createType(kind);
15521559 type.symbol = symbol;
@@ -1921,6 +1928,19 @@ namespace ts {
19211928 return result;
19221929 }
19231930
1931+ function replaceTrueFalseWithBoolean(types: Type[]): Type[] {
1932+ if (contains(types, trueType) && contains(types, falseType)) {
1933+ const result: Type[] = [];
1934+ for (const t of types) {
1935+ if (t !== falseType) {
1936+ result.push(t === trueType ? booleanType : t);
1937+ }
1938+ }
1939+ return result;
1940+ }
1941+ return types;
1942+ }
1943+
19241944 function visibilityToString(flags: NodeFlags) {
19251945 if (flags === NodeFlags.Private) {
19261946 return "private";
@@ -2213,7 +2233,12 @@ namespace ts {
22132233 if (flags & TypeFormatFlags.InElementType) {
22142234 writePunctuation(writer, SyntaxKind.OpenParenToken);
22152235 }
2216- writeTypeList(type.types, type.flags & TypeFlags.Union ? SyntaxKind.BarToken : SyntaxKind.AmpersandToken);
2236+ if (type.flags & TypeFlags.Union) {
2237+ writeTypeList(replaceTrueFalseWithBoolean(type.types), SyntaxKind.BarToken);
2238+ }
2239+ else {
2240+ writeTypeList(type.types, SyntaxKind.AmpersandToken);
2241+ }
22172242 if (flags & TypeFormatFlags.InElementType) {
22182243 writePunctuation(writer, SyntaxKind.CloseParenToken);
22192244 }
@@ -5661,7 +5686,7 @@ namespace ts {
56615686 if (type.flags & TypeFlags.Tuple) {
56625687 return createTupleType(instantiateList((<TupleType>type).elementTypes, mapper, instantiateType));
56635688 }
5664- if (type.flags & TypeFlags.Union) {
5689+ if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive) ) {
56655690 return getUnionType(instantiateList((<UnionType>type).types, mapper, instantiateType), /*noSubtypeReduction*/ true);
56665691 }
56675692 if (type.flags & TypeFlags.Intersection) {
@@ -6070,10 +6095,10 @@ namespace ts {
60706095 // Note that these checks are specifically ordered to produce correct results.
60716096 if (source.flags & TypeFlags.Union) {
60726097 if (relation === comparableRelation) {
6073- result = someTypeRelatedToType(source as UnionType, target, reportErrors);
6098+ result = someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive) );
60746099 }
60756100 else {
6076- result = eachTypeRelatedToType(source as UnionType, target, reportErrors);
6101+ result = eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive) );
60776102 }
60786103
60796104 if (result) {
@@ -6110,12 +6135,9 @@ namespace ts {
61106135 }
61116136 }
61126137 if (target.flags & TypeFlags.Union) {
6113- if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive))) {
6138+ if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive) )) {
61146139 return result;
61156140 }
6116- if (source === booleanType && contains((<UnionType>target).types, trueType) && contains((<UnionType>target).types, falseType)) {
6117- return Ternary.True;
6118- }
61196141 }
61206142 }
61216143
@@ -6969,7 +6991,9 @@ namespace ts {
69696991 }
69706992
69716993 function isUnitUnionType(type: Type): boolean {
6972- return type.flags & TypeFlags.Union ? !forEach((<UnionType>type).types, t => !isUnitType(t)) : isUnitType(type);
6994+ return type.flags & TypeFlags.Boolean ? true :
6995+ type.flags & TypeFlags.Union ? !forEach((<UnionType>type).types, t => !isUnitType(t)) :
6996+ isUnitType(type);
69736997 }
69746998
69756999 function getBaseTypeOfUnitType(type: Type): Type {
@@ -6981,10 +7005,6 @@ namespace ts {
69817005 type;
69827006 }
69837007
6984- function isUnionWithTrueOrFalse(type: Type) {
6985- return type.flags & TypeFlags.Union && (contains((<UnionType>type).types, trueType) || contains((<UnionType>type).types, falseType));
6986- }
6987-
69887008 /**
69897009 * Check if a Type was written as a tuple type literal.
69907010 * Prefer using isTupleLikeType() unless the use of `elementTypes` is required.
@@ -7001,12 +7021,15 @@ namespace ts {
70017021 return result;
70027022 }
70037023
7024+ // Returns the String, Number, Boolean, StringLiteral, NumberLiteral, BooleanLiteral, Void, Undefined, or Null
7025+ // flags for the string, number, boolean, "", 0, false, void, undefined, or null types respectively. Returns
7026+ // no flags for all other types (including non-falsy literal types).
70047027 function getFalsyFlags(type: Type): TypeFlags {
7005- return type === emptyStringType ? TypeFlags.StringLiteral :
7006- type === zeroType ? TypeFlags.NumberLiteral :
7007- type === falseType ? TypeFlags.BooleanLiteral :
7008- type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((<UnionType> type).types) :
7009- type.flags & TypeFlags.AlwaysPossiblyFalsy ;
7028+ return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((<UnionType>type).types) :
7029+ type.flags & TypeFlags.StringLiteral ? type === emptyStringType ? TypeFlags.StringLiteral : 0 :
7030+ type.flags & TypeFlags.NumberLiteral ? type === zeroType ? TypeFlags.NumberLiteral : 0 :
7031+ type.flags & TypeFlags.BooleanLiteral ? type === falseType ? TypeFlags.BooleanLiteral : 0 :
7032+ type.flags & TypeFlags.PossiblyFalsy ;
70107033 }
70117034
70127035 function includeFalsyTypes(type: Type, flags: TypeFlags) {
@@ -10403,8 +10426,11 @@ namespace ts {
1040310426 checkClassPropertyAccess(node, left, apparentType, prop);
1040410427 }
1040510428
10406- const propType = prop.flags & SymbolFlags.EnumMember && getParentOfSymbol(prop).flags & SymbolFlags.ConstEnum &&
10407- isLiteralTypeContext(<Expression>node) ? getDeclaredTypeOfSymbol(prop) : getTypeOfSymbol(prop);
10429+ let propType = getTypeOfSymbol(prop);
10430+ if (prop.flags & SymbolFlags.EnumMember && getParentOfSymbol(prop).flags & SymbolFlags.ConstEnum && isLiteralContextForType(<Expression>node, propType)) {
10431+ propType = getDeclaredTypeOfSymbol(prop);
10432+ }
10433+
1040810434 // Only compute control flow type if this is a property access expression that isn't an
1040910435 // assignment target, and the referenced property was declared as a variable, property,
1041010436 // accessor, or optional method.
@@ -12460,7 +12486,7 @@ namespace ts {
1246012486
1246112487 function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
1246212488 const operandType = checkExpression(node.operand);
12463- if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral && isLiteralTypeContext (node)) {
12489+ if (node.operator === SyntaxKind.MinusToken && node.operand.kind === SyntaxKind.NumericLiteral && isLiteralContextForType (node, numberType )) {
1246412490 return getLiteralTypeForText(TypeFlags.NumberLiteral, "" + -(<LiteralExpression>node.operand).text);
1246512491 }
1246612492 switch (node.operator) {
@@ -12475,7 +12501,6 @@ namespace ts {
1247512501 const facts = getTypeFacts(operandType) & (TypeFacts.Truthy | TypeFacts.Falsy);
1247612502 return facts === TypeFacts.Truthy ? falseType :
1247712503 facts === TypeFacts.Falsy ? trueType :
12478- isUnionWithTrueOrFalse(operandType) ? trueFalseType :
1247912504 booleanType;
1248012505 case SyntaxKind.PlusPlusToken:
1248112506 case SyntaxKind.MinusMinusToken:
@@ -12866,7 +12891,7 @@ namespace ts {
1286612891 return checkInExpression(left, right, leftType, rightType);
1286712892 case SyntaxKind.AmpersandAmpersandToken:
1286812893 return getTypeFacts(leftType) & TypeFacts.Truthy ?
12869- strictNullChecks ? includeFalsyTypes(rightType, getFalsyFlags(leftType)) : rightType :
12894+ includeFalsyTypes(rightType, getFalsyFlags(strictNullChecks ? leftType : getBaseTypeOfUnitType( rightType))) :
1287012895 leftType;
1287112896 case SyntaxKind.BarBarToken:
1287212897 return getTypeFacts(leftType) & TypeFacts.Falsy ?
@@ -13000,45 +13025,64 @@ namespace ts {
1300013025 return getUnionType([type1, type2]);
1300113026 }
1300213027
13003- function isLiteralUnionType(type: Type): boolean {
13004- return type.flags & TypeFlags.Literal ? true :
13005- type.flags & TypeFlags.Enum ? (type.symbol.flags & SymbolFlags.EnumMember) !== 0 :
13006- type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isLiteralUnionType) :
13007- false;
13028+ function typeContainsEnumLiteral(type: Type, enumType: Type) {
13029+ if (type.flags & TypeFlags.Union) {
13030+ for (const t of (<UnionType>type).types) {
13031+ if (t.flags & TypeFlags.Enum && t.symbol.flags & SymbolFlags.EnumMember && t.symbol.parent === enumType.symbol) {
13032+ return true;
13033+ }
13034+ }
13035+ }
13036+ if (type.flags & TypeFlags.Enum) {
13037+ return type.symbol.flags & SymbolFlags.EnumMember && type.symbol.parent === enumType.symbol;
13038+ }
13039+ return false;
1300813040 }
1300913041
13010- function hasLiteralContextualType(node: Expression) {
13011- const contextualType = getContextualType(node);
13012- if (!contextualType) {
13013- return false;
13042+ function isLiteralContextForType(node: Expression, type: Type) {
13043+ if (isLiteralTypeLocation(node)) {
13044+ return true;
1301413045 }
13015- if (contextualType.flags & TypeFlags.TypeParameter) {
13016- const apparentType = getApparentTypeOfTypeParameter(<TypeParameter>contextualType);
13017- if (apparentType.flags & (TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.BooleanLike)) {
13018- return true;
13046+ let contextualType = getContextualType(node);
13047+ if (contextualType) {
13048+ if (contextualType.flags & TypeFlags.TypeParameter) {
13049+ const apparentType = getApparentTypeOfTypeParameter(<TypeParameter>contextualType);
13050+ // If the type parameter is constrained to the base primitive type we're checking for,
13051+ // consider this a literal context. For example, given a type parameter 'T extends string',
13052+ // this causes us to infer string literal types for T.
13053+ if (type === apparentType) {
13054+ return true;
13055+ }
13056+ contextualType = apparentType;
13057+ }
13058+ if (type.flags & TypeFlags.String) {
13059+ return maybeTypeOfKind(contextualType, TypeFlags.StringLiteral);
13060+ }
13061+ if (type.flags & TypeFlags.Number) {
13062+ return maybeTypeOfKind(contextualType, TypeFlags.NumberLiteral);
13063+ }
13064+ if (type.flags & TypeFlags.Boolean) {
13065+ return maybeTypeOfKind(contextualType, TypeFlags.BooleanLiteral) && !isTypeAssignableTo(booleanType, contextualType);
13066+ }
13067+ if (type.flags & TypeFlags.Enum && type.symbol.flags & SymbolFlags.ConstEnum) {
13068+ return typeContainsEnumLiteral(contextualType, type);
1301913069 }
1302013070 }
13021- return isLiteralUnionType(contextualType);
13022- }
13023-
13024- function isLiteralTypeContext(node: Expression) {
13025- return isLiteralTypeLocation(node) || hasLiteralContextualType(node);
13071+ return false;
1302613072 }
1302713073
1302813074 function checkLiteralExpression(node: Expression): Type {
1302913075 if (node.kind === SyntaxKind.NumericLiteral) {
1303013076 checkGrammarNumericLiteral(<LiteralExpression>node);
1303113077 }
13032- const hasLiteralType = isLiteralTypeContext(node);
1303313078 switch (node.kind) {
1303413079 case SyntaxKind.StringLiteral:
13035- return hasLiteralType ? getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text) : stringType;
13080+ return isLiteralContextForType(node, stringType) ? getLiteralTypeForText(TypeFlags.StringLiteral, (<LiteralExpression>node).text) : stringType;
1303613081 case SyntaxKind.NumericLiteral:
13037- return hasLiteralType ? getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text) : numberType;
13082+ return isLiteralContextForType(node, numberType) ? getLiteralTypeForText(TypeFlags.NumberLiteral, (<LiteralExpression>node).text) : numberType;
1303813083 case SyntaxKind.TrueKeyword:
13039- return hasLiteralType ? trueType : booleanType;
1304013084 case SyntaxKind.FalseKeyword:
13041- return hasLiteralType ? falseType : booleanType;
13085+ return isLiteralContextForType(node, booleanType) ? node.kind === SyntaxKind.TrueKeyword ? trueType : falseType : booleanType;
1304213086 }
1304313087 }
1304413088
@@ -18324,6 +18368,9 @@ namespace ts {
1832418368 }
1832518369 }
1832618370
18371+ // The built-in boolean type is 'true | false', also mark 'false | true' as a boolean type
18372+ createBooleanType([falseType, trueType]);
18373+
1832718374 // Setup global builtins
1832818375 addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0);
1832918376
0 commit comments