Merge pull request #942 from Microsoft/unionTypeFixes

Union type fixes and optimizations
This commit is contained in:
Anders Hejlsberg 2014-10-22 14:48:22 -07:00
commit 051478d7d5
3 changed files with 264 additions and 255 deletions

View File

@ -94,11 +94,10 @@ module ts {
getSymbolsInScope: getSymbolsInScope,
getSymbolInfo: getSymbolInfo,
getTypeOfNode: getTypeOfNode,
getApparentType: getApparentType,
typeToString: typeToString,
getSymbolDisplayBuilder: getSymbolDisplayBuilder,
symbolToString: symbolToString,
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType,
getAugmentedPropertiesOfType: getAugmentedPropertiesOfType,
getRootSymbols: getRootSymbols,
getContextualType: getContextualType,
getFullyQualifiedName: getFullyQualifiedName,
@ -679,17 +678,17 @@ module ts {
return result || emptyArray;
}
function setObjectTypeMembers(type: ObjectType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedObjectType {
(<ResolvedObjectType>type).members = members;
(<ResolvedObjectType>type).properties = getNamedMembers(members);
(<ResolvedObjectType>type).callSignatures = callSignatures;
(<ResolvedObjectType>type).constructSignatures = constructSignatures;
if (stringIndexType) (<ResolvedObjectType>type).stringIndexType = stringIndexType;
if (numberIndexType) (<ResolvedObjectType>type).numberIndexType = numberIndexType;
return <ResolvedObjectType>type;
function setObjectTypeMembers(type: ObjectType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedType {
(<ResolvedType>type).members = members;
(<ResolvedType>type).properties = getNamedMembers(members);
(<ResolvedType>type).callSignatures = callSignatures;
(<ResolvedType>type).constructSignatures = constructSignatures;
if (stringIndexType) (<ResolvedType>type).stringIndexType = stringIndexType;
if (numberIndexType) (<ResolvedType>type).numberIndexType = numberIndexType;
return <ResolvedType>type;
}
function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedObjectType {
function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexType: Type, numberIndexType: Type): ResolvedType {
return setObjectTypeMembers(createObjectType(TypeFlags.Anonymous, symbol),
members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}
@ -1217,7 +1216,7 @@ module ts {
}
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
var resolved = resolveObjectTypeMembers(type);
var resolved = resolveObjectOrUnionTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
writePunctuation(writer, SyntaxKind.OpenBraceToken);
@ -1296,7 +1295,7 @@ module ts {
for (var i = 0; i < resolved.properties.length; i++) {
var p = resolved.properties[i];
var t = getTypeOfSymbol(p);
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfType(t).length) {
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) {
var signatures = getSignaturesOfType(t, SignatureKind.Call);
for (var j = 0; j < signatures.length; j++) {
buildSymbolDisplay(p, writer);
@ -1552,25 +1551,6 @@ module ts {
}
}
function getApparentType(type: Type): ApparentType {
if (type.flags & TypeFlags.TypeParameter) {
do {
type = getConstraintOfTypeParameter(<TypeParameter>type);
} while (type && type.flags & TypeFlags.TypeParameter);
if (!type) type = emptyObjectType;
}
if (type.flags & TypeFlags.StringLike) {
type = globalStringType;
}
else if (type.flags & TypeFlags.NumberLike) {
type = globalNumberType;
}
else if (type.flags & TypeFlags.Boolean) {
type = globalBooleanType;
}
return <ApparentType>type;
}
function getTypeOfPrototypeProperty(prototype: Symbol): Type {
// TypeScript 1.0 spec (April 2014): 8.4
// Every class automatically contains a static property member named 'prototype',
@ -1786,15 +1766,6 @@ module ts {
return links.type;
}
function getTypeOfUnionProperty(symbol: Symbol): Type {
var links = getSymbolLinks(symbol);
if (!links.type) {
var types = map(links.unionType.types, t => getTypeOfSymbol(getPropertyOfType(getApparentType(t), symbol.name)));
links.type = getUnionType(types);
}
return links.type;
}
function getTypeOfSymbol(symbol: Symbol): Type {
if (symbol.flags & SymbolFlags.Instantiated) {
return getTypeOfInstantiatedSymbol(symbol);
@ -1814,9 +1785,6 @@ module ts {
if (symbol.flags & SymbolFlags.Import) {
return getTypeOfImport(symbol);
}
if (symbol.flags & SymbolFlags.UnionProperty) {
return getTypeOfUnionProperty(symbol);
}
return unknownType;
}
@ -2034,7 +2002,7 @@ module ts {
if (type.baseTypes.length) {
members = createSymbolTable(type.declaredProperties);
forEach(type.baseTypes, baseType => {
addInheritedMembers(members, getPropertiesOfType(baseType));
addInheritedMembers(members, getPropertiesOfObjectType(baseType));
callSignatures = concatenate(callSignatures, getSignaturesOfType(baseType, SignatureKind.Call));
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(baseType, SignatureKind.Construct));
stringIndexType = stringIndexType || getIndexTypeOfType(baseType, IndexKind.String);
@ -2054,7 +2022,7 @@ module ts {
var numberIndexType = target.declaredNumberIndexType ? instantiateType(target.declaredNumberIndexType, mapper) : undefined;
forEach(target.baseTypes, baseType => {
var instantiatedBaseType = instantiateType(baseType, mapper);
addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType));
addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType));
callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call));
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct));
stringIndexType = stringIndexType || getIndexTypeOfType(instantiatedBaseType, IndexKind.String);
@ -2107,7 +2075,7 @@ module ts {
}
function resolveTupleTypeMembers(type: TupleType) {
var arrayType = resolveObjectTypeMembers(createArrayType(getUnionType(type.elementTypes)));
var arrayType = resolveObjectOrUnionTypeMembers(createArrayType(getUnionType(type.elementTypes)));
var members = createTupleTypeMemberSymbols(type.elementTypes);
addInheritedMembers(members, arrayType.properties);
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType);
@ -2164,42 +2132,13 @@ module ts {
}
function resolveUnionTypeMembers(type: UnionType) {
var types: Type[] = [];
forEach(type.types, t => {
var apparentType = getApparentType(t);
if (!contains(types, apparentType)) {
types.push(apparentType);
}
});
if (types.length <= 1) {
var resolved = types.length ? resolveObjectTypeMembers(types[0]) : emptyObjectType;
setObjectTypeMembers(type, resolved.members, resolved.callSignatures, resolved.constructSignatures, resolved.stringIndexType, resolved.numberIndexType);
return;
}
var members: SymbolTable = {};
forEach(getPropertiesOfType(types[0]), prop => {
for (var i = 1; i < types.length; i++) {
if (!getPropertyOfType(types[i], prop.name)) {
return;
}
}
var symbol = <TransientSymbol>createSymbol(SymbolFlags.UnionProperty | SymbolFlags.Transient, prop.name);
symbol.unionType = type;
symbol.declarations = [];
for (var i = 0; i < types.length; i++) {
var s = getPropertyOfType(types[i], prop.name);
if (s.declarations)
symbol.declarations.push.apply(symbol.declarations, s.declarations);
}
members[prop.name] = symbol;
});
var callSignatures = getUnionSignatures(types, SignatureKind.Call);
var constructSignatures = getUnionSignatures(types, SignatureKind.Construct);
var stringIndexType = getUnionIndexType(types, IndexKind.String);
var numberIndexType = getUnionIndexType(types, IndexKind.Number);
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
// The members and properties collections are empty for union types. To get all properties of a union
// type use getPropertiesOfType (only the language service uses this).
var callSignatures = getUnionSignatures(type.types, SignatureKind.Call);
var constructSignatures = getUnionSignatures(type.types, SignatureKind.Construct);
var stringIndexType = getUnionIndexType(type.types, IndexKind.String);
var numberIndexType = getUnionIndexType(type.types, IndexKind.Number);
setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}
function resolveAnonymousTypeMembers(type: ObjectType) {
@ -2230,7 +2169,7 @@ module ts {
}
if (classType.baseTypes.length) {
members = createSymbolTable(getNamedMembers(members));
addInheritedMembers(members, getPropertiesOfType(getTypeOfSymbol(classType.baseTypes[0].symbol)));
addInheritedMembers(members, getPropertiesOfObjectType(getTypeOfSymbol(classType.baseTypes[0].symbol)));
}
}
var stringIndexType: Type = undefined;
@ -2239,8 +2178,8 @@ module ts {
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}
function resolveObjectTypeMembers(type: ObjectType): ResolvedObjectType {
if (!(<ResolvedObjectType>type).members) {
function resolveObjectOrUnionTypeMembers(type: ObjectType): ResolvedType {
if (!(<ResolvedType>type).members) {
if (type.flags & (TypeFlags.Class | TypeFlags.Interface)) {
resolveClassOrInterfaceMembers(<InterfaceType>type);
}
@ -2257,60 +2196,173 @@ module ts {
resolveTypeReferenceMembers(<TypeReference>type);
}
}
return <ResolvedObjectType>type;
return <ResolvedType>type;
}
function getPropertiesOfType(type: Type): Symbol[] {
// Return properties of an object type or an empty array for other types
function getPropertiesOfObjectType(type: Type): Symbol[] {
if (type.flags & TypeFlags.ObjectType) {
return resolveObjectTypeMembers(<ObjectType>type).properties;
return resolveObjectOrUnionTypeMembers(<ObjectType>type).properties;
}
return emptyArray;
}
// If the given type is an object type and that type has a property by the given name, return
// the symbol for that property. Otherwise return undefined.
function getPropertyOfObjectType(type: Type, name: string): Symbol {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
if (hasProperty(resolved.members, name)) {
var symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
}
}
}
function getPropertiesOfUnionType(type: UnionType): Symbol[] {
var result: Symbol[] = [];
forEach(getPropertiesOfType(type.types[0]), prop => {
var unionProp = getPropertyOfUnionType(type, prop.name);
if (unionProp) {
result.push(unionProp);
}
});
return result;
}
function getPropertiesOfType(type: Type): Symbol[] {
if (type.flags & TypeFlags.Union) {
return getPropertiesOfUnionType(<UnionType>type);
}
return getPropertiesOfObjectType(getApparentType(type));
}
// For a type parameter, return the base constraint of the type parameter. For the string, number, and
// boolean 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 {
if (type.flags & TypeFlags.TypeParameter) {
do {
type = getConstraintOfTypeParameter(<TypeParameter>type);
} while (type && type.flags & TypeFlags.TypeParameter);
if (!type) {
type = emptyObjectType;
}
}
if (type.flags & TypeFlags.StringLike) {
type = globalStringType;
}
else if (type.flags & TypeFlags.NumberLike) {
type = globalNumberType;
}
else if (type.flags & TypeFlags.Boolean) {
type = globalBooleanType;
}
return type;
}
function createUnionProperty(unionType: UnionType, name: string): Symbol {
var types = unionType.types;
var props: Symbol[];
for (var i = 0; i < types.length; i++) {
var type = getApparentType(types[i]);
if (type !== unknownType) {
var prop = getPropertyOfType(type, name);
if (!prop) {
return undefined;
}
if (!props) {
props = [prop];
}
else {
props.push(prop);
}
}
}
var propTypes: Type[] = [];
var declarations: Declaration[] = [];
for (var i = 0; i < props.length; i++) {
var prop = props[i];
if (prop.declarations) {
declarations.push.apply(declarations, prop.declarations);
}
propTypes.push(getTypeOfSymbol(prop));
}
var result = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.UnionProperty, name);
result.unionType = unionType;
result.declarations = declarations;
result.type = getUnionType(propTypes);
return result;
}
function getPropertyOfUnionType(type: UnionType, name: string): Symbol {
var properties = type.resolvedProperties || (type.resolvedProperties = {});
if (hasProperty(properties, name)) {
return properties[name];
}
var property = createUnionProperty(type, name);
if (property) {
properties[name] = property;
}
return property;
}
// Return the symbol for the property with the given name in the given type. Creates synthetic union properties when
// necessary, maps primtive types and type parameters are to their apparent types, and augments with properties from
// Object and Function as appropriate.
function getPropertyOfType(type: Type, name: string): Symbol {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectTypeMembers(<ObjectType>type);
if (hasProperty(resolved.members, name)) {
var symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
if (type.flags & TypeFlags.Union) {
return getPropertyOfUnionType(<UnionType>type, name);
}
if (!(type.flags & TypeFlags.ObjectType)) {
type = getApparentType(type);
if (!(type.flags & TypeFlags.ObjectType)) {
return undefined;
}
}
}
function getPropertyOfApparentType(type: ApparentType, name: string): Symbol {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectTypeMembers(<ObjectType>type);
if (hasProperty(resolved.members, name)) {
var symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
var resolved = resolveObjectOrUnionTypeMembers(type);
if (hasProperty(resolved.members, name)) {
var symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
var symbol = getPropertyOfType(globalFunctionType, name);
if (symbol) return symbol;
}
return getPropertyOfType(globalObjectType, name);
}
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
var symbol = getPropertyOfObjectType(globalFunctionType, name);
if (symbol) return symbol;
}
return getPropertyOfObjectType(globalObjectType, name);
}
function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectTypeMembers(<ObjectType>type);
function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] {
if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
var resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures;
}
return emptyArray;
}
function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectTypeMembers(<ObjectType>type);
// Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and
// maps primtive types and type parameters are to their apparent types.
function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
return getSignaturesOfObjectOrUnionType(getApparentType(type), kind);
}
function getIndexTypeOfObjectOrUnionType(type: Type, kind: IndexKind): Type {
if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
var resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
return kind === IndexKind.String ? resolved.stringIndexType : resolved.numberIndexType;
}
}
// Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
// maps primtive types and type parameters are to their apparent types.
function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind);
}
// Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
// type checking functions).
function getTypeParametersFromDeclaration(typeParameterDeclarations: TypeParameterDeclaration[]): TypeParameter[] {
@ -2472,7 +2524,7 @@ module ts {
// will result in a different declaration kind.
if (!signature.isolatedSignatureType) {
var isConstructor = signature.declaration.kind === SyntaxKind.Constructor || signature.declaration.kind === SyntaxKind.ConstructSignature;
var type = <ResolvedObjectType>createObjectType(TypeFlags.Anonymous | TypeFlags.FromSignature);
var type = <ResolvedType>createObjectType(TypeFlags.Anonymous | TypeFlags.FromSignature);
type.members = emptySymbols;
type.properties = emptyArray;
type.callSignatures = !isConstructor ? [signature] : emptyArray;
@ -3007,8 +3059,8 @@ module ts {
}
function instantiateAnonymousType(type: ObjectType, mapper: TypeMapper): ObjectType {
var result = <ResolvedObjectType>createObjectType(TypeFlags.Anonymous, type.symbol);
result.properties = instantiateList(getPropertiesOfType(type), mapper, instantiateSymbol);
var result = <ResolvedType>createObjectType(TypeFlags.Anonymous, type.symbol);
result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol);
result.members = createSymbolTable(result.properties);
result.callSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Call), mapper, instantiateSignature);
result.constructSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Construct), mapper, instantiateSignature);
@ -3065,9 +3117,9 @@ module ts {
function getTypeWithoutConstructors(type: Type): Type {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectTypeMembers(<ObjectType>type);
var resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
if (resolved.constructSignatures.length) {
var result = <ResolvedObjectType>createObjectType(TypeFlags.Anonymous, type.symbol);
var result = <ResolvedType>createObjectType(TypeFlags.Anonymous, type.symbol);
result.members = resolved.members;
result.properties = resolved.properties;
result.callSignatures = resolved.callSignatures;
@ -3129,7 +3181,7 @@ module ts {
for (var i = 0, len = type.baseTypes.length; i < len; ++i) {
var base = type.baseTypes[i];
var properties = getPropertiesOfType(base);
var properties = getPropertiesOfObjectType(base);
for (var j = 0, proplen = properties.length; j < proplen; ++j) {
var prop = properties[j];
if (!hasProperty(seen, prop.name)) {
@ -3390,10 +3442,10 @@ module ts {
if (relation === identityRelation) {
return propertiesIdenticalTo(source, target, reportErrors);
}
var properties = getPropertiesOfType(target);
var properties = getPropertiesOfObjectType(target);
for (var i = 0; i < properties.length; i++) {
var targetProp = properties[i];
var sourceProp = getPropertyOfApparentType(<ApparentType>source, targetProp.name);
var sourceProp = getPropertyOfType(source, targetProp.name);
if (sourceProp !== targetProp) {
if (!sourceProp) {
if (relation === subtypeRelation || !isOptionalProperty(targetProp)) {
@ -3467,14 +3519,14 @@ module ts {
}
function propertiesIdenticalTo(source: ObjectType, target: ObjectType, reportErrors: boolean): boolean {
var sourceProperties = getPropertiesOfType(source);
var targetProperties = getPropertiesOfType(target);
var sourceProperties = getPropertiesOfObjectType(source);
var targetProperties = getPropertiesOfObjectType(target);
if (sourceProperties.length !== targetProperties.length) {
return false;
}
for (var i = 0, len = sourceProperties.length; i < len; ++i) {
var sourceProp = sourceProperties[i];
var targetProp = getPropertyOfType(target, sourceProp.name);
var targetProp = getPropertyOfObjectType(target, sourceProp.name);
if (!targetProp || !isPropertyIdenticalToRecursive(sourceProp, targetProp, reportErrors, isRelatedTo)) {
return false;
}
@ -3721,7 +3773,7 @@ module ts {
}
function getWidenedTypeOfObjectLiteral(type: Type): Type {
var properties = getPropertiesOfType(type);
var properties = getPropertiesOfObjectType(type);
if (properties.length) {
var widenedTypes: Type[] = [];
var propTypeWasWidened: boolean = false;
@ -3903,10 +3955,10 @@ module ts {
}
function inferFromProperties(source: Type, target: Type) {
var properties = getPropertiesOfType(target);
var properties = getPropertiesOfObjectType(target);
for (var i = 0; i < properties.length; i++) {
var targetProp = properties[i];
var sourceProp = getPropertyOfType(source, targetProp.name);
var sourceProp = getPropertyOfObjectType(source, targetProp.name);
if (sourceProp) {
inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
}
@ -4203,7 +4255,7 @@ module ts {
if (!isTypeSubtypeOf(rightType, globalFunctionType)) {
return type;
}
var prototypeProperty = getPropertyOfType(getApparentType(rightType), "prototype");
var prototypeProperty = getPropertyOfType(rightType, "prototype");
if (!prototypeProperty) {
return type;
}
@ -4559,23 +4611,23 @@ module ts {
function getTypeOfPropertyOfContextualType(type: Type, name: string) {
return applyToContextualType(type, t => {
var prop = getPropertyOfType(t, name);
var prop = getPropertyOfObjectType(t, name);
return prop ? getTypeOfSymbol(prop) : undefined;
});
}
function getIndexTypeOfContextualType(type: Type, kind: IndexKind) {
return applyToContextualType(type, t => getIndexTypeOfType(t, kind));
return applyToContextualType(type, t => getIndexTypeOfObjectOrUnionType(t, kind));
}
// Return true if the given contextual type is a tuple-like type
function contextualTypeIsTupleType(type: Type): boolean {
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getPropertyOfType(t, "0")) : getPropertyOfType(type, "0"));
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getPropertyOfObjectType(t, "0")) : getPropertyOfObjectType(type, "0"));
}
// Return true if the given contextual type provides an index signature of the given kind
function contextualTypeHasIndexSignature(type: Type, kind: IndexKind): boolean {
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getIndexTypeOfType(t, kind)) : getIndexTypeOfType(type, kind));
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getIndexTypeOfObjectOrUnionType(t, kind)) : getIndexTypeOfObjectOrUnionType(type, kind));
}
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
@ -4649,17 +4701,16 @@ module ts {
return undefined;
}
// Return the single non-generic signature in the given type, or undefined if none exists
// If the given type is an object or union type, if that type has a single signature, and if
// that signature is non-generic, return the signature. Otherwise return undefined.
function getNonGenericSignature(type: Type): Signature {
var signatures = getSignaturesOfType(type, SignatureKind.Call);
if (signatures.length !== 1) {
return undefined;
var signatures = getSignaturesOfObjectOrUnionType(type, SignatureKind.Call);
if (signatures.length === 1) {
var signature = signatures[0];
if (!signature.typeParameters) {
return signature;
}
}
var signature = signatures[0];
if (signature.typeParameters) {
return undefined;
}
return signature;
}
// Return the contextual signature for a given expression node. A contextual type provides a
@ -4846,11 +4897,11 @@ module ts {
if (type === unknownType) return type;
if (type !== anyType) {
var apparentType = getApparentType(getWidenedType(type));
if (<Type>apparentType === unknownType) {
if (apparentType === unknownType) {
// handle cases when type is Type parameter with invalid constraint
return unknownType;
}
var prop = getPropertyOfApparentType(apparentType, node.right.text);
var prop = getPropertyOfType(apparentType, node.right.text);
if (!prop) {
if (node.right.text) {
error(node.right, Diagnostics.Property_0_does_not_exist_on_type_1, identifierToString(node.right), typeToString(type));
@ -4881,8 +4932,7 @@ module ts {
function isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean {
var type = checkExpression(node.left);
if (type !== unknownType && type !== anyType) {
var apparentType = getApparentType(getWidenedType(type));
var prop = getPropertyOfApparentType(apparentType, propertyName);
var prop = getPropertyOfType(getWidenedType(type), propertyName);
if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) {
if (node.left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) {
return false;
@ -4898,8 +4948,10 @@ module ts {
}
function checkIndexedAccess(node: IndexedAccess): Type {
var objectType = checkExpression(node.object);
// Obtain base constraint such that we can bail out if the constraint is an unknown type
var objectType = getApparentType(checkExpression(node.object));
var indexType = checkExpression(node.index);
if (objectType === unknownType) return unknownType;
// TypeScript 1.0 spec (April 2014): 4.10 Property Access
@ -4912,14 +4964,9 @@ module ts {
// - Otherwise, if IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of type Any.
// See if we can index as a property.
var apparentType = getApparentType(objectType);
if (<Type>apparentType === unknownType) {
// handle cases when objectType is type parameter with invalid type
return unknownType;
}
if (node.index.kind === SyntaxKind.StringLiteral || node.index.kind === SyntaxKind.NumericLiteral) {
var name = (<LiteralExpression>node.index).text;
var prop = getPropertyOfApparentType(apparentType, name);
var prop = getPropertyOfType(objectType, name);
if (prop) {
return getTypeOfSymbol(prop);
}
@ -4930,14 +4977,14 @@ module ts {
// Try to use a number indexer.
if (indexType.flags & (TypeFlags.Any | TypeFlags.NumberLike)) {
var numberIndexType = getIndexTypeOfType(apparentType, IndexKind.Number);
var numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
if (numberIndexType) {
return numberIndexType;
}
}
// Try to use string indexing.
var stringIndexType = getIndexTypeOfType(apparentType, IndexKind.String);
var stringIndexType = getIndexTypeOfType(objectType, IndexKind.String);
if (stringIndexType) {
return stringIndexType;
}
@ -5000,7 +5047,7 @@ module ts {
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
function getSingleCallSignature(type: Type): Signature {
if (type.flags & TypeFlags.ObjectType) {
var resolved = resolveObjectTypeMembers(<ObjectType>type);
var resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 &&
resolved.properties.length === 0 && !resolved.stringIndexType && !resolved.numberIndexType) {
return resolved.callSignatures[0];
@ -5222,18 +5269,13 @@ module ts {
}
var funcType = checkExpression(node.func);
if (funcType === unknownType) {
var apparentType = getApparentType(funcType);
if (apparentType === unknownType) {
// Another error has already been reported
return resolveErrorCall(node);
}
var apparentType = getApparentType(funcType);
if (<Type>apparentType === unknownType) {
// handler cases when funcType is type parameter with invalid constraint
// Another error was already reported
return resolveErrorCall(node);
}
// Technically, this signatures list may be incomplete. We are taking the apparent type,
// but we are not including call signatures that may have been added to the Object or
// Function interface, since they have none by default. This is a bit of a leap of faith
@ -5271,10 +5313,7 @@ module ts {
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
var expressionType = checkExpression(node.func);
if (expressionType === unknownType) {
// Another error has already been reported
return resolveErrorCall(node);
}
// TS 1.0 spec: 4.11
// If ConstructExpr is of type Any, Args can be any argument
// list and the result of the operation is of type Any.
@ -5282,7 +5321,6 @@ module ts {
if (node.typeArguments) {
error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments);
}
return resolveUntypedCall(node);
}
@ -5292,9 +5330,8 @@ module ts {
// signatures for overload resolution.The result type of the function call becomes
// the result type of the operation.
expressionType = getApparentType(expressionType);
if (<Type>expressionType === unknownType) {
// handler cases when original expressionType is a type parameter with invalid constraint
// another error has already been reported
if (expressionType === unknownType) {
// Another error has already been reported
return resolveErrorCall(node);
}
@ -6996,7 +7033,7 @@ module ts {
// for interfaces property and indexer might be inherited from different bases
// check if any base class already has both property and indexer.
// check should be performed only if 'type' is the first type that brings property\indexer together
var someBaseClassHasBothPropertyAndIndexer = forEach((<InterfaceType>type).baseTypes, base => getPropertyOfType(base, prop.name) && getIndexTypeOfType(base, indexKind));
var someBaseClassHasBothPropertyAndIndexer = forEach((<InterfaceType>type).baseTypes, base => getPropertyOfObjectType(base, prop.name) && getIndexTypeOfType(base, indexKind));
errorNode = someBaseClassHasBothPropertyAndIndexer ? undefined : type.symbol.declarations[0];
}
@ -7016,7 +7053,7 @@ module ts {
var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
if (stringIndexType || numberIndexType) {
forEach(getPropertiesOfType(type), prop => {
forEach(getPropertiesOfObjectType(type), prop => {
var propType = getTypeOfSymbol(prop);
checkIndexConstraintForProperty(prop, propType, declaredStringIndexer, stringIndexType, IndexKind.String);
checkIndexConstraintForProperty(prop, propType, declaredNumberIndexer, numberIndexType, IndexKind.Number);
@ -7148,7 +7185,7 @@ module ts {
// derived class instance member variables and accessors, but not by other kinds of members.
// NOTE: assignability is checked in checkClassDeclaration
var baseProperties = getPropertiesOfType(baseType);
var baseProperties = getPropertiesOfObjectType(baseType);
for (var i = 0, len = baseProperties.length; i < len; ++i) {
var base = getTargetSymbol(baseProperties[i]);
@ -7156,7 +7193,7 @@ module ts {
continue;
}
var derived = getTargetSymbol(getPropertyOfType(type, base.name));
var derived = getTargetSymbol(getPropertyOfObjectType(type, base.name));
if (derived) {
var baseDeclarationFlags = getDeclarationFlagsFromSymbol(base);
var derivedDeclarationFlags = getDeclarationFlagsFromSymbol(derived);
@ -8079,8 +8116,8 @@ module ts {
var objectType = checkExpression((<IndexedAccess>node.parent).object);
if (objectType === unknownType) return undefined;
var apparentType = getApparentType(objectType);
if (<Type>apparentType === unknownType) return undefined;
return getPropertyOfApparentType(apparentType, (<LiteralExpression>node).text);
if (apparentType === unknownType) return undefined;
return getPropertyOfType(apparentType, (<LiteralExpression>node).text);
}
break;
}
@ -8139,49 +8176,27 @@ module ts {
return checkExpression(expr);
}
function getAugmentedPropertiesOfApparentType(type: Type): Symbol[]{
var apparentType = getApparentType(type);
if (apparentType.flags & TypeFlags.ObjectType) {
// Augment the apparent type with Function and Object members as applicable
var propertiesByName: Map<Symbol> = {};
var results: Symbol[] = [];
forEach(getPropertiesOfType(apparentType), s => {
propertiesByName[s.name] = s;
results.push(s);
});
var resolved = resolveObjectTypeMembers(<ObjectType>type);
forEachValue(resolved.members, s => {
if (symbolIsValue(s) && !propertiesByName[s.name]) {
propertiesByName[s.name] = s;
results.push(s);
// Return the list of properties of the given type, augmented with properties from Function
// if the type has call or construct signatures
function getAugmentedPropertiesOfType(type: Type): Symbol[] {
var type = getApparentType(type);
var propsByName = createSymbolTable(getPropertiesOfType(type));
if (getSignaturesOfType(type, SignatureKind.Call).length || getSignaturesOfType(type, SignatureKind.Construct).length) {
forEach(getPropertiesOfType(globalFunctionType), p => {
if (!hasProperty(propsByName, p.name)) {
propsByName[p.name] = p;
}
});
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
forEach(getPropertiesOfType(globalFunctionType), s => {
if (!propertiesByName[s.name]) {
propertiesByName[s.name] = s;
results.push(s);
}
});
}
return results;
}
else {
return getPropertiesOfType(<Type>apparentType);
}
return getNamedMembers(propsByName);
}
function getRootSymbols(symbol: Symbol): Symbol[] {
function getRootSymbols(symbol: Symbol): Symbol[]{
if (symbol.flags & SymbolFlags.UnionProperty) {
var symbols: Symbol[] = [];
var name = symbol.name;
forEach(getSymbolLinks(symbol).unionType.types, t => {
symbols.push(getPropertyOfType(getApparentType(t), name));
symbols.push(getPropertyOfType(t, name));
});
return symbols;
}

View File

@ -644,19 +644,18 @@ module ts {
getParentOfSymbol(symbol: Symbol): Symbol;
getTypeOfSymbol(symbol: Symbol): Type;
getPropertiesOfType(type: Type): Symbol[];
getPropertyOfType(type: Type, propetyName: string): Symbol;
getPropertyOfType(type: Type, propertyName: string): Symbol;
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
getReturnTypeOfSignature(signature: Signature): Type;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolInfo(node: Node): Symbol;
getTypeOfNode(node: Node): Type;
getApparentType(type: Type): ApparentType;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
getSymbolDisplayBuilder(): SymbolDisplayBuilder;
getFullyQualifiedName(symbol: Symbol): string;
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
getAugmentedPropertiesOfType(type: Type): Symbol[];
getRootSymbols(symbol: Symbol): Symbol[];
getContextualType(node: Node): Type;
getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature;
@ -781,21 +780,20 @@ module ts {
ConstructSignature = 0x00010000, // Construct signature
IndexSignature = 0x00020000, // Index signature
TypeParameter = 0x00040000, // Type parameter
UnionProperty = 0x00080000, // Property in union type
// Export markers (see comment in declareModuleMember in binder)
ExportValue = 0x00100000, // Exported value marker
ExportType = 0x00200000, // Exported type marker
ExportNamespace = 0x00400000, // Exported namespace marker
ExportValue = 0x00080000, // Exported value marker
ExportType = 0x00100000, // Exported type marker
ExportNamespace = 0x00200000, // Exported namespace marker
Import = 0x00800000, // Import
Instantiated = 0x01000000, // Instantiated symbol
Merged = 0x02000000, // Merged symbol (created during program binding)
Transient = 0x04000000, // Transient symbol (created during type check)
Prototype = 0x08000000, // Prototype property (no source representation)
Undefined = 0x10000000, // Symbol for the undefined
Import = 0x00400000, // Import
Instantiated = 0x00800000, // Instantiated symbol
Merged = 0x01000000, // Merged symbol (created during program binding)
Transient = 0x02000000, // Transient symbol (created during type check)
Prototype = 0x04000000, // Prototype property (no source representation)
UnionProperty = 0x08000000, // Property in union type
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | UnionProperty,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter,
Namespace = ValueModule | NamespaceModule,
@ -910,7 +908,7 @@ module ts {
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
StringLike = String | StringLiteral,
NumberLike = Number | Enum,
ObjectType = Class | Interface | Reference | Tuple | Union | Anonymous,
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
}
// Properties common to all types
@ -933,12 +931,6 @@ module ts {
// Object types (TypeFlags.ObjectType)
export interface ObjectType extends Type { }
export interface ApparentType extends Type {
// This property is not used. It is just to make the type system think ApparentType
// is a strict subtype of Type.
_apparentTypeBrand: any;
}
// Class and interface types (TypeFlags.Class and TypeFlags.Interface)
export interface InterfaceType extends ObjectType {
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
@ -968,12 +960,13 @@ module ts {
baseArrayType: TypeReference; // Array<T> where T is best common type of element types
}
export interface UnionType extends ObjectType {
types: Type[]; // Constituent types
export interface UnionType extends Type {
types: Type[]; // Constituent types
resolvedProperties: SymbolTable; // Cache of resolved properties
}
// Resolved object type
export interface ResolvedObjectType extends ObjectType {
// Resolved object or union type
export interface ResolvedType extends ObjectType, UnionType {
members: SymbolTable; // Properties by name
properties: Symbol[]; // Properties
callSignatures: Signature[]; // Call signatures of type

View File

@ -575,7 +575,7 @@ module ts {
return this.checker.getPropertyOfType(this, propertyName);
}
getApparentProperties(): Symbol[] {
return this.checker.getAugmentedPropertiesOfApparentType(this);
return this.checker.getAugmentedPropertiesOfType(this);
}
getCallSignatures(): Signature[] {
return this.checker.getSignaturesOfType(this, SignatureKind.Call);
@ -2569,10 +2569,9 @@ module ts {
}
var type = typeInfoResolver.getTypeOfNode(mappedNode);
var apparentType = type && typeInfoResolver.getApparentType(type);
if (apparentType) {
if (type) {
// Filter private properties
forEach(apparentType.getApparentProperties(), symbol => {
forEach(type.getApparentProperties(), symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(mappedNode.parent), symbol.name)) {
symbols.push(symbol);
}
@ -2726,19 +2725,21 @@ module ts {
if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement;
if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement;
if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement;
if (flags & SymbolFlags.Property) return ScriptElementKind.memberVariableElement;
if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement;
if (flags & SymbolFlags.UnionProperty) {
return forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => {
var rootSymbolFlags = rootSymbol.getFlags();
if (rootSymbolFlags & SymbolFlags.Property) {
return ScriptElementKind.memberVariableElement;
}
if (rootSymbolFlags & SymbolFlags.GetAccessor) return ScriptElementKind.memberVariableElement;
if (rootSymbolFlags & SymbolFlags.SetAccessor) return ScriptElementKind.memberVariableElement;
Debug.assert(rootSymbolFlags & SymbolFlags.Method);
}) || ScriptElementKind.memberFunctionElement;
if (flags & SymbolFlags.Property) {
if (flags & SymbolFlags.UnionProperty) {
return forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => {
var rootSymbolFlags = rootSymbol.getFlags();
if (rootSymbolFlags & SymbolFlags.Property) {
return ScriptElementKind.memberVariableElement;
}
if (rootSymbolFlags & SymbolFlags.GetAccessor) return ScriptElementKind.memberVariableElement;
if (rootSymbolFlags & SymbolFlags.SetAccessor) return ScriptElementKind.memberVariableElement;
Debug.assert(rootSymbolFlags & SymbolFlags.Method);
}) || ScriptElementKind.memberFunctionElement;
}
return ScriptElementKind.memberVariableElement;
}
return ScriptElementKind.unknown;