Merge branch 'master' into optimizeMaps

This commit is contained in:
Anders Hejlsberg
2016-08-12 13:31:37 -07:00
37 changed files with 1533 additions and 242 deletions

View File

@@ -1886,18 +1886,17 @@ namespace ts {
}
function bindExportAssignment(node: ExportAssignment | BinaryExpression) {
const boundExpression = node.kind === SyntaxKind.ExportAssignment ? (<ExportAssignment>node).expression : (<BinaryExpression>node).right;
if (!container.symbol || !container.symbol.exports) {
// Export assignment in some sort of block construct
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
}
else if (boundExpression.kind === SyntaxKind.Identifier && node.kind === SyntaxKind.ExportAssignment) {
// An export default clause with an identifier exports all meanings of that identifier
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
else {
// An export default clause with an expression exports a value
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node)
// An export default clause with an EntityNameExpression exports all meanings of that identifier
? SymbolFlags.Alias
// An export default clause with any other expression exports a value
: SymbolFlags.Property;
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
}

View File

@@ -245,7 +245,8 @@ namespace ts {
NEUndefinedOrNull = 1 << 19, // x != undefined / x != null
Truthy = 1 << 20, // x
Falsy = 1 << 21, // !x
All = (1 << 22) - 1,
Discriminatable = 1 << 22, // May have discriminant property
All = (1 << 23) - 1,
// The following members encode facts about particular kinds of types for use in the getTypeFacts function.
// The presence of a particular fact means that the given test is true for some (and possibly all) values
// of that kind of type.
@@ -275,9 +276,9 @@ namespace ts {
TrueFacts = BaseBooleanFacts | Truthy,
SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable,
ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable,
FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
@@ -659,7 +660,7 @@ namespace ts {
// Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and
// the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with
// the given name can be found.
function resolveName(location: Node, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol {
function resolveName(location: Node | undefined, name: string, meaning: SymbolFlags, nameNotFoundMessage: DiagnosticMessage, nameArg: string | Identifier): Symbol {
let result: Symbol;
let lastLocation: Node;
let propertyWithInvalidInitializer: Node;
@@ -876,7 +877,8 @@ namespace ts {
if (!result) {
if (nameNotFoundMessage) {
if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) &&
if (!errorLocation ||
!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) &&
!checkAndReportErrorForExtendingInterface(errorLocation)) {
error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg));
}
@@ -925,7 +927,7 @@ namespace ts {
}
function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: string, nameArg: string | Identifier): boolean {
if (!errorLocation || (errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(<Identifier>errorLocation)) || isInTypeQuery(errorLocation))) {
if ((errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(<Identifier>errorLocation)) || isInTypeQuery(errorLocation))) {
return false;
}
@@ -963,28 +965,30 @@ namespace ts {
function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean {
let parentClassExpression = errorLocation;
while (parentClassExpression) {
const kind = parentClassExpression.kind;
if (kind === SyntaxKind.Identifier || kind === SyntaxKind.PropertyAccessExpression) {
parentClassExpression = parentClassExpression.parent;
continue;
}
if (kind === SyntaxKind.ExpressionWithTypeArguments) {
break;
}
return false;
}
if (!parentClassExpression) {
return false;
}
const expression = (<ExpressionWithTypeArguments>parentClassExpression).expression;
if (resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) {
const expression = getEntityNameForExtendingInterface(errorLocation);
const isError = !!(expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true));
if (isError) {
error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression));
return true;
}
return false;
return isError;
}
/**
* Climbs up parents to an ExpressionWithTypeArguments, and returns its expression,
* but returns undefined if that expression is not an EntityNameExpression.
*/
function getEntityNameForExtendingInterface(node: Node): EntityNameExpression | undefined {
switch (node.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.PropertyAccessExpression:
return node.parent ? getEntityNameForExtendingInterface(node.parent) : undefined;
case SyntaxKind.ExpressionWithTypeArguments:
Debug.assert(isEntityNameExpression((<ExpressionWithTypeArguments>node).expression));
return <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression;
default:
return undefined;
}
}
function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void {
Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0);
@@ -1028,7 +1032,7 @@ namespace ts {
}
function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration {
return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
return find(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
}
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
@@ -1163,7 +1167,7 @@ namespace ts {
}
function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
return resolveEntityName(<Identifier>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
return resolveEntityName(<EntityNameExpression>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
}
function getTargetOfAliasDeclaration(node: Declaration): Symbol {
@@ -1273,7 +1277,7 @@ namespace ts {
}
// Resolves a qualified name and any involved aliases
function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean): Symbol {
function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean): Symbol | undefined {
if (nodeIsMissing(name)) {
return undefined;
}
@@ -1288,7 +1292,7 @@ namespace ts {
}
}
else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
const left = name.kind === SyntaxKind.QualifiedName ? (<QualifiedName>name).left : (<PropertyAccessExpression>name).expression;
const left = name.kind === SyntaxKind.QualifiedName ? (<QualifiedName>name).left : (<PropertyAccessEntityNameExpression>name).expression;
const right = name.kind === SyntaxKind.QualifiedName ? (<QualifiedName>name).right : (<PropertyAccessExpression>name).name;
const namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors);
@@ -1533,8 +1537,8 @@ namespace ts {
function createType(flags: TypeFlags): Type {
const result = new Type(checker, flags);
result.id = typeCount;
typeCount++;
result.id = typeCount;
return result;
}
@@ -1842,7 +1846,7 @@ namespace ts {
}
}
function isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult {
function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult {
// get symbol of the first identifier of the entityName
let meaning: SymbolFlags;
if (entityName.parent.kind === SyntaxKind.TypeQuery || isExpressionWithTypeArgumentsInClassExtendsClause(entityName.parent)) {
@@ -3672,7 +3676,7 @@ namespace ts {
const baseTypeNodes = getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration);
if (baseTypeNodes) {
for (const node of baseTypeNodes) {
if (isSupportedExpressionWithTypeArguments(node)) {
if (isEntityNameExpression(node.expression)) {
const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true);
if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) {
return false;
@@ -3993,6 +3997,9 @@ namespace ts {
return createTypeReference((<TypeReference>type).target,
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
}
if (type.flags & TypeFlags.Tuple) {
return createTupleType((type as TupleType).elementTypes, thisArgument);
}
return type;
}
@@ -4096,7 +4103,8 @@ namespace ts {
function resolveTupleTypeMembers(type: TupleType) {
const arrayElementType = getUnionType(type.elementTypes);
// Make the tuple type itself the 'this' type by including an extra type argument
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type]));
// (Unless it's provided in the case that the tuple is a type parameter constraint)
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type.thisType || type]));
const members = createTupleTypeMemberSymbols(type.elementTypes);
addInheritedMembers(members, arrayType.properties);
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
@@ -4930,24 +4938,27 @@ namespace ts {
}
function getTypeListId(types: Type[]) {
let result = "";
if (types) {
switch (types.length) {
case 1:
return "" + types[0].id;
case 2:
return types[0].id + "," + types[1].id;
default:
let result = "";
for (let i = 0; i < types.length; i++) {
if (i > 0) {
result += ",";
}
result += types[i].id;
}
return result;
const length = types.length;
let i = 0;
while (i < length) {
const startId = types[i].id;
let count = 1;
while (i + count < length && types[i + count].id === startId + count) {
count++;
}
if (result.length) {
result += ",";
}
result += startId;
if (count > 1) {
result += ":" + count;
}
i += count;
}
}
return "";
return result;
}
// This function is used to propagate certain flags when creating new object type references and union types.
@@ -5030,7 +5041,7 @@ namespace ts {
return getDeclaredTypeOfSymbol(symbol);
}
function getTypeReferenceName(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): LeftHandSideExpression | EntityName {
function getTypeReferenceName(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): EntityNameOrEntityNameExpression | undefined {
switch (node.kind) {
case SyntaxKind.TypeReference:
return (<TypeReferenceNode>node).typeName;
@@ -5039,8 +5050,9 @@ namespace ts {
case SyntaxKind.ExpressionWithTypeArguments:
// We only support expressions that are simple qualified names. For other
// expressions this produces undefined.
if (isSupportedExpressionWithTypeArguments(<ExpressionWithTypeArguments>node)) {
return (<ExpressionWithTypeArguments>node).expression;
const expr = (<ExpressionWithTypeArguments>node).expression;
if (isEntityNameExpression(expr)) {
return expr;
}
// fall through;
@@ -5051,7 +5063,7 @@ namespace ts {
function resolveTypeReferenceName(
node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference,
typeReferenceName: LeftHandSideExpression | EntityName) {
typeReferenceName: EntityNameExpression | EntityName) {
if (!typeReferenceName) {
return unknownSymbol;
@@ -5092,15 +5104,14 @@ namespace ts {
const typeReferenceName = getTypeReferenceName(node);
symbol = resolveTypeReferenceName(node, typeReferenceName);
type = getTypeReferenceType(node, symbol);
links.resolvedSymbol = symbol;
links.resolvedType = type;
}
else {
// We only support expressions that are simple qualified names. For other expressions this produces undefined.
const typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (<TypeReferenceNode>node).typeName :
isSupportedExpressionWithTypeArguments(<ExpressionWithTypeArguments>node) ? (<ExpressionWithTypeArguments>node).expression :
undefined;
const typeNameOrExpression: EntityNameOrEntityNameExpression = node.kind === SyntaxKind.TypeReference
? (<TypeReferenceNode>node).typeName
: isEntityNameExpression((<ExpressionWithTypeArguments>node).expression)
? <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression
: undefined;
symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
type = symbol === unknownSymbol ? unknownType :
symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) :
@@ -5219,15 +5230,16 @@ namespace ts {
return links.resolvedType;
}
function createTupleType(elementTypes: Type[]) {
const id = getTypeListId(elementTypes);
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes));
function createTupleType(elementTypes: Type[], thisType?: Type) {
const id = getTypeListId(elementTypes) + "," + (thisType ? thisType.id : 0);
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes, thisType));
}
function createNewTupleType(elementTypes: Type[]) {
function createNewTupleType(elementTypes: Type[], thisType?: Type) {
const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0);
const type = <TupleType>createObjectType(TypeFlags.Tuple | propagatedFlags);
type.elementTypes = elementTypes;
type.thisType = thisType;
return type;
}
@@ -5329,12 +5341,12 @@ namespace ts {
}
}
// We deduplicate the constituent types based on object identity. If the subtypeReduction flag is
// specified we also reduce the constituent type set to only include types that aren't subtypes of
// other types. Subtype reduction is expensive for large union types and is possible only when union
// We sort and deduplicate the constituent types based on object identity. If the subtypeReduction
// flag is specified we also reduce the constituent type set to only include types that aren't subtypes
// of other types. Subtype reduction is expensive for large union types and is possible only when union
// types are known not to circularly reference themselves (as is the case with union types created by
// expression constructs such as array literals and the || and ?: operators). Named types can
// circularly reference themselves and therefore cannot be deduplicated during their declaration.
// circularly reference themselves and therefore cannot be subtype reduced during their declaration.
// For example, "type Item = string | (() => Item" is a named type that circularly references itself.
function getUnionType(types: Type[], subtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
if (types.length === 0) {
@@ -5356,15 +5368,23 @@ namespace ts {
typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType :
neverType;
}
else if (typeSet.length === 1) {
return typeSet[0];
return getUnionTypeFromSortedList(typeSet, aliasSymbol, aliasTypeArguments);
}
// This function assumes the constituent type list is sorted and deduplicated.
function getUnionTypeFromSortedList(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
if (types.length === 0) {
return neverType;
}
const id = getTypeListId(typeSet);
if (types.length === 1) {
return types[0];
}
const id = getTypeListId(types);
let type = unionTypes[id];
if (!type) {
const propagatedFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable);
const propagatedFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | propagatedFlags);
type.types = typeSet;
type.types = types;
type.aliasSymbol = aliasSymbol;
type.aliasTypeArguments = aliasTypeArguments;
}
@@ -7826,18 +7846,25 @@ namespace ts {
}
function isDiscriminantProperty(type: Type, name: string) {
if (type) {
const nonNullType = getNonNullableType(type);
if (nonNullType.flags & TypeFlags.Union) {
const prop = getPropertyOfType(nonNullType, name);
if (prop && prop.flags & SymbolFlags.SyntheticProperty) {
if ((<TransientSymbol>prop).isDiscriminantProperty === undefined) {
(<TransientSymbol>prop).isDiscriminantProperty = !(<TransientSymbol>prop).hasCommonType &&
isUnitUnionType(getTypeOfSymbol(prop));
}
return (<TransientSymbol>prop).isDiscriminantProperty;
if (type && type.flags & TypeFlags.Union) {
let prop = getPropertyOfType(type, name);
if (!prop) {
// The type may be a union that includes nullable or primitive types. If filtering
// those out produces a different type, get the property from that type instead.
// Effectively, we're checking if this *could* be a discriminant property once nullable
// and primitive types are removed by other type guards.
const filteredType = getTypeWithFacts(type, TypeFacts.Discriminatable);
if (filteredType !== type && filteredType.flags & TypeFlags.Union) {
prop = getPropertyOfType(filteredType, name);
}
}
if (prop && prop.flags & SymbolFlags.SyntheticProperty) {
if ((<TransientSymbol>prop).isDiscriminantProperty === undefined) {
(<TransientSymbol>prop).isDiscriminantProperty = !(<TransientSymbol>prop).hasCommonType &&
isUnitUnionType(getTypeOfSymbol(prop));
}
return (<TransientSymbol>prop).isDiscriminantProperty;
}
}
return false;
}
@@ -7885,10 +7912,10 @@ namespace ts {
// For example, when a variable of type number | string | boolean is assigned a value of type number | boolean,
// we remove type string.
function getAssignmentReducedType(declaredType: UnionType, assignedType: Type) {
if (declaredType !== assignedType && declaredType.flags & TypeFlags.Union) {
const reducedTypes = filter(declaredType.types, t => typeMaybeAssignableTo(assignedType, t));
if (reducedTypes.length) {
return reducedTypes.length === 1 ? reducedTypes[0] : getUnionType(reducedTypes);
if (declaredType !== assignedType) {
const reducedType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t));
if (reducedType !== neverType) {
return reducedType;
}
}
return declaredType;
@@ -7902,6 +7929,14 @@ namespace ts {
return result;
}
function isFunctionObjectType(type: ObjectType): boolean {
// We do a quick check for a "bind" property before performing the more expensive subtype
// check. This gives us a quicker out in the common case where an object type is not a function.
const resolved = resolveStructuredTypeMembers(type);
return !!(resolved.callSignatures.length || resolved.constructSignatures.length ||
hasProperty(resolved.members, "bind") && isTypeSubtypeOf(type, globalFunctionType));
}
function getTypeFacts(type: Type): TypeFacts {
const flags = type.flags;
if (flags & TypeFlags.String) {
@@ -7930,8 +7965,7 @@ namespace ts {
type === falseType ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
}
if (flags & TypeFlags.ObjectType) {
const resolved = resolveStructuredTypeMembers(type);
return resolved.callSignatures.length || resolved.constructSignatures.length || isTypeSubtypeOf(type, globalFunctionType) ?
return isFunctionObjectType(<ObjectType>type) ?
strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
}
@@ -7955,26 +7989,7 @@ namespace ts {
}
function getTypeWithFacts(type: Type, include: TypeFacts) {
if (!(type.flags & TypeFlags.Union)) {
return getTypeFacts(type) & include ? type : neverType;
}
let firstType: Type;
let types: Type[];
for (const t of (type as UnionType).types) {
if (getTypeFacts(t) & include) {
if (!firstType) {
firstType = t;
}
else {
if (!types) {
types = [firstType];
}
types.push(t);
}
}
}
return types ? getUnionType(types) :
firstType ? firstType : neverType;
return filterType(type, t => (getTypeFacts(t) & include) !== 0);
}
function getTypeWithDefault(type: Type, defaultExpression: Expression) {
@@ -8150,9 +8165,12 @@ namespace ts {
}
function filterType(type: Type, f: (t: Type) => boolean): Type {
return type.flags & TypeFlags.Union ?
getUnionType(filter((<UnionType>type).types, f)) :
f(type) ? type : neverType;
if (type.flags & TypeFlags.Union) {
const types = (<UnionType>type).types;
const filtered = filter(types, f);
return filtered === types ? type : getUnionTypeFromSortedList(filtered);
}
return f(type) ? type : neverType;
}
function isIncomplete(flowType: FlowType) {
@@ -8490,7 +8508,7 @@ namespace ts {
}
if (assumeTrue && !(type.flags & TypeFlags.Union)) {
// We narrow a non-union type to an exact primitive type if the non-union type
// is a supertype of that primtive type. For example, type 'any' can be narrowed
// is a supertype of that primitive type. For example, type 'any' can be narrowed
// to one of the primitive types.
const targetType = getProperty(typeofTypesByName, literal.text);
if (targetType && isTypeSubtypeOf(targetType, type)) {
@@ -8579,9 +8597,9 @@ namespace ts {
// If the current type is a union type, remove all constituents that couldn't be instances of
// the candidate type. If one or more constituents remain, return a union of those.
if (type.flags & TypeFlags.Union) {
const assignableConstituents = filter((<UnionType>type).types, t => isTypeInstanceOf(t, candidate));
if (assignableConstituents.length) {
return getUnionType(assignableConstituents);
const assignableType = filterType(type, t => isTypeInstanceOf(t, candidate));
if (assignableType !== neverType) {
return assignableType;
}
}
// If the candidate type is a subtype of the target type, narrow to the candidate type.
@@ -16367,7 +16385,7 @@ namespace ts {
const implementedTypeNodes = getClassImplementsHeritageClauseElements(node);
if (implementedTypeNodes) {
for (const typeRefNode of implementedTypeNodes) {
if (!isSupportedExpressionWithTypeArguments(typeRefNode)) {
if (!isEntityNameExpression(typeRefNode.expression)) {
error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments);
}
checkTypeReferenceNode(typeRefNode);
@@ -16609,7 +16627,7 @@ namespace ts {
checkObjectTypeForDuplicateDeclarations(node);
}
forEach(getInterfaceBaseTypeNodes(node), heritageElement => {
if (!isSupportedExpressionWithTypeArguments(heritageElement)) {
if (!isEntityNameExpression(heritageElement.expression)) {
error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments);
}
checkTypeReferenceNode(heritageElement);
@@ -17074,20 +17092,21 @@ namespace ts {
}
}
function getFirstIdentifier(node: EntityName | Expression): Identifier {
while (true) {
if (node.kind === SyntaxKind.QualifiedName) {
node = (<QualifiedName>node).left;
}
else if (node.kind === SyntaxKind.PropertyAccessExpression) {
node = (<PropertyAccessExpression>node).expression;
}
else {
break;
}
function getFirstIdentifier(node: EntityNameOrEntityNameExpression): Identifier {
switch (node.kind) {
case SyntaxKind.Identifier:
return <Identifier>node;
case SyntaxKind.QualifiedName:
do {
node = (<QualifiedName>node).left;
} while (node.kind !== SyntaxKind.Identifier);
return <Identifier>node;
case SyntaxKind.PropertyAccessExpression:
do {
node = (<PropertyAccessEntityNameExpression>node).expression;
} while (node.kind !== SyntaxKind.Identifier);
return <Identifier>node;
}
Debug.assert(node.kind === SyntaxKind.Identifier);
return <Identifier>node;
}
function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean {
@@ -17786,7 +17805,7 @@ namespace ts {
return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined;
}
function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol {
function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol | undefined {
if (isDeclarationName(entityName)) {
return getSymbolOfNode(entityName.parent);
}
@@ -17805,22 +17824,20 @@ namespace ts {
}
}
if (entityName.parent.kind === SyntaxKind.ExportAssignment) {
return resolveEntityName(<Identifier>entityName,
if (entityName.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(<Identifier | PropertyAccessExpression>entityName)) {
return resolveEntityName(<EntityNameExpression>entityName,
/*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
}
if (entityName.kind !== SyntaxKind.PropertyAccessExpression) {
if (isInRightSideOfImportOrExportAssignment(<EntityName>entityName)) {
// Since we already checked for ExportAssignment, this really could only be an Import
const importEqualsDeclaration = <ImportEqualsDeclaration>getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration);
Debug.assert(importEqualsDeclaration !== undefined);
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>entityName, importEqualsDeclaration, /*dontResolveAlias*/ true);
}
if (entityName.kind !== SyntaxKind.PropertyAccessExpression && isInRightSideOfImportOrExportAssignment(<EntityName>entityName)) {
// Since we already checked for ExportAssignment, this really could only be an Import
const importEqualsDeclaration = <ImportEqualsDeclaration>getAncestor(entityName, SyntaxKind.ImportEqualsDeclaration);
Debug.assert(importEqualsDeclaration !== undefined);
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>entityName, importEqualsDeclaration, /*dontResolveAlias*/ true);
}
if (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
entityName = <QualifiedName | PropertyAccessExpression>entityName.parent;
entityName = <QualifiedName | PropertyAccessEntityNameExpression>entityName.parent;
}
if (isHeritageClauseElementIdentifier(<EntityName>entityName)) {
@@ -18530,7 +18547,7 @@ namespace ts {
};
// defined here to avoid outer scope pollution
function getTypeReferenceDirectivesForEntityName(node: EntityName | PropertyAccessExpression): string[] {
function getTypeReferenceDirectivesForEntityName(node: EntityNameOrEntityNameExpression): string[] {
// program does not have any files with type reference directives - bail out
if (!fileToDirective) {
return undefined;

View File

@@ -97,7 +97,7 @@ namespace ts {
* returns a truthy value, then returns that value.
* If no such value is found, the callback is applied to each element of array and undefined is returned.
*/
export function forEach<T, U>(array: T[], callback: (element: T, index: number) => U): U {
export function forEach<T, U>(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array) {
for (let i = 0, len = array.length; i < len; i++) {
const result = callback(array[i], i);
@@ -109,6 +109,17 @@ namespace ts {
return undefined;
}
/** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */
export function find<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
for (let i = 0, len = array.length; i < len; i++) {
const result = callback(array[i], i);
if (result) {
return result;
}
}
Debug.fail();
}
export function contains<T>(array: T[], value: T): boolean {
if (array) {
for (const v of array) {
@@ -152,17 +163,29 @@ namespace ts {
return count;
}
/**
* Filters an array by a predicate function. Returns the same array instance if the predicate is
* true for all elements, otherwise returns a new array instance containing the filtered subset.
*/
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
let result: T[];
if (array) {
result = [];
for (const item of array) {
if (f(item)) {
result.push(item);
const len = array.length;
let i = 0;
while (i < len && f(array[i])) i++;
if (i < len) {
const result = array.slice(0, i);
i++;
while (i < len) {
const item = array[i];
if (f(item)) {
result.push(item);
}
i++;
}
return result;
}
}
return result;
return array;
}
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {

View File

@@ -441,7 +441,7 @@ namespace ts {
}
}
function emitEntityName(entityName: EntityName | PropertyAccessExpression) {
function emitEntityName(entityName: EntityNameOrEntityNameExpression) {
const visibilityResult = resolver.isEntityNameVisible(entityName,
// Aliases can be written asynchronously so use correct enclosing declaration
entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration);
@@ -452,9 +452,9 @@ namespace ts {
}
function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) {
if (isSupportedExpressionWithTypeArguments(node)) {
if (isEntityNameExpression(node.expression)) {
Debug.assert(node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression);
emitEntityName(<Identifier | PropertyAccessExpression>node.expression);
emitEntityName(node.expression);
if (node.typeArguments) {
write("<");
emitCommaList(node.typeArguments, emitType);
@@ -1019,7 +1019,7 @@ namespace ts {
}
function emitTypeOfTypeReference(node: ExpressionWithTypeArguments) {
if (isSupportedExpressionWithTypeArguments(node)) {
if (isEntityNameExpression(node.expression)) {
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError);
}
else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) {

View File

@@ -119,49 +119,31 @@ namespace ts {
}
function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
let jsonContent: { typings?: string, types?: string, main?: string };
try {
const jsonText = state.host.readFile(packageJsonPath);
jsonContent = jsonText ? <{ typings?: string, types?: string, main?: string }>JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
jsonContent = {};
const jsonContent = readJson(packageJsonPath, state.host);
function tryReadFromField(fieldName: string) {
if (hasProperty(jsonContent, fieldName)) {
const typesFile = (<any>jsonContent)[fieldName];
if (typeof typesFile === "string") {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
return typesFilePath;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof typesFile);
}
}
}
}
let typesFile: string;
let fieldName: string;
// first try to read content of 'typings' section (backward compatibility)
if (jsonContent.typings) {
if (typeof jsonContent.typings === "string") {
fieldName = "typings";
typesFile = jsonContent.typings;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "typings", typeof jsonContent.typings);
}
}
}
// then read 'types'
if (!typesFile && jsonContent.types) {
if (typeof jsonContent.types === "string") {
fieldName = "types";
typesFile = jsonContent.types;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "types", typeof jsonContent.types);
}
}
}
if (typesFile) {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
const typesFilePath = tryReadFromField("typings") || tryReadFromField("types");
if (typesFilePath) {
return typesFilePath;
}
// Use the main module for inferring types if no types package specified and the allowJs is set
if (state.compilerOptions.allowJs && jsonContent.main && typeof jsonContent.main === "string") {
if (state.traceEnabled) {
@@ -173,6 +155,17 @@ namespace ts {
return undefined;
}
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
try {
const jsonText = host.readFile(path);
return jsonText ? JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
return {};
}
}
const typeReferenceExtensions = [".d.ts"];
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
@@ -717,7 +710,7 @@ namespace ts {
}
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
const packageJsonPath = combinePaths(candidate, "package.json");
const packageJsonPath = pathToPackageJson(candidate);
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
if (directoryExists && state.host.fileExists(packageJsonPath)) {
if (state.traceEnabled) {
@@ -747,6 +740,10 @@ namespace ts {
return loadModuleFromFile(combinePaths(candidate, "index"), extensions, failedLookupLocation, !directoryExists, state);
}
function pathToPackageJson(directory: string): string {
return combinePaths(directory, "package.json");
}
function loadModuleFromNodeModulesFolder(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState): string {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
@@ -1070,15 +1067,21 @@ namespace ts {
}
// Walk the primary type lookup locations
let result: string[] = [];
const result: string[] = [];
if (host.directoryExists && host.getDirectories) {
const typeRoots = getEffectiveTypeRoots(options, host);
if (typeRoots) {
for (const root of typeRoots) {
if (host.directoryExists(root)) {
for (const typeDirectivePath of host.getDirectories(root)) {
// Return just the type directive names
result = result.concat(getBaseFileName(normalizePath(typeDirectivePath)));
const normalized = normalizePath(typeDirectivePath);
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host.fileExists(packageJsonPath) && readJson(packageJsonPath, host).typings === null;
if (!isNotNeededPackage) {
// Return just the type directive names
result.push(getBaseFileName(normalized));
}
}
}
}

View File

@@ -986,13 +986,19 @@ namespace ts {
multiLine?: boolean;
}
export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression;
export type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression;
// @kind(SyntaxKind.PropertyAccessExpression)
export interface PropertyAccessExpression extends MemberExpression, Declaration {
expression: LeftHandSideExpression;
name: Identifier;
}
export type IdentifierOrPropertyAccess = Identifier | PropertyAccessExpression;
/** Brand for a PropertyAccessExpression which, like a QualifiedName, consists of a sequence of identifiers separated by dots. */
export interface PropertyAccessEntityNameExpression extends PropertyAccessExpression {
_propertyAccessExpressionLikeQualifiedNameBrand?: any;
expression: EntityNameExpression;
}
// @kind(SyntaxKind.ElementAccessExpression)
export interface ElementAccessExpression extends MemberExpression {
@@ -2035,7 +2041,7 @@ namespace ts {
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult;
isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult;
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult;
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
getReferencedValueDeclaration(reference: Identifier): Declaration;
@@ -2044,7 +2050,7 @@ namespace ts {
moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean;
isArgumentsLocalBinding(node: Identifier): boolean;
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
getTypeReferenceDirectivesForEntityName(name: EntityName | PropertyAccessExpression): string[];
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
}
@@ -2373,6 +2379,7 @@ namespace ts {
export interface TupleType extends ObjectType {
elementTypes: Type[]; // Element types
thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters)
}
export interface UnionOrIntersectionType extends Type {

View File

@@ -1033,14 +1033,14 @@ namespace ts {
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression {
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
if (node) {
switch (node.kind) {
case SyntaxKind.TypeReference:
return (<TypeReferenceNode>node).typeName;
case SyntaxKind.ExpressionWithTypeArguments:
return (<ExpressionWithTypeArguments>node).expression;
Debug.assert(isEntityNameExpression((<ExpressionWithTypeArguments>node).expression));
return <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression;
case SyntaxKind.Identifier:
case SyntaxKind.QualifiedName:
return (<EntityName><Node>node);
@@ -1694,8 +1694,8 @@ namespace ts {
// import * as <symbol> from ...
// import { x as <symbol> } from ...
// export { x as <symbol> } from ...
// export = ...
// export default ...
// export = <EntityNameExpression>
// export default <EntityNameExpression>
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
@@ -1703,7 +1703,11 @@ namespace ts {
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier;
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node);
}
export function exportAssignmentIsAlias(node: ExportAssignment): boolean {
return isEntityNameExpression(node.expression);
}
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) {
@@ -2676,22 +2680,9 @@ namespace ts {
isClassLike(node.parent.parent);
}
// Returns false if this heritage clause element's expression contains something unsupported
// (i.e. not a name or dotted name).
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
}
function isSupportedExpressionWithTypeArgumentsRest(node: Expression): boolean {
if (node.kind === SyntaxKind.Identifier) {
return true;
}
else if (isPropertyAccessExpression(node)) {
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
}
else {
return false;
}
export function isEntityNameExpression(node: Expression): node is EntityNameExpression {
return node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((<PropertyAccessExpression>node).expression);
}
export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {