diff --git a/scripts/errorCheck.ts b/scripts/errorCheck.ts index 77892cb8f0c..36489c5f312 100644 --- a/scripts/errorCheck.ts +++ b/scripts/errorCheck.ts @@ -4,84 +4,84 @@ let async = require('async'); let glob = require('glob'); fs.readFile('src/compiler/diagnosticMessages.json', 'utf-8', (err, data) => { - if (err) { - throw err; - } - - let messages = JSON.parse(data); - let keys = Object.keys(messages); - console.log('Loaded ' + keys.length + ' errors'); + if (err) { + throw err; + } - for (let k of keys) { - messages[k]['seen'] = false; - } + let messages = JSON.parse(data); + let keys = Object.keys(messages); + console.log('Loaded ' + keys.length + ' errors'); - let errRegex = /\(\d+,\d+\): error TS([^:]+):/g; + for (let k of keys) { + messages[k]['seen'] = false; + } - let baseDir = 'tests/baselines/reference/'; - fs.readdir(baseDir, (err, files) => { - files = files.filter(f => f.indexOf('.errors.txt') > 0); - let tasks: Array<(callback: () => void) => void> = []; - files.forEach(f => tasks.push(done => { - fs.readFile(baseDir + f, 'utf-8', (err, baseline) => { - if (err) throw err; + let errRegex = /\(\d+,\d+\): error TS([^:]+):/g; - let g: string[]; - while (g = errRegex.exec(baseline)) { - var errCode = +g[1]; - let msg = keys.filter(k => messages[k].code === errCode)[0]; - messages[msg]['seen'] = true; - } + let baseDir = 'tests/baselines/reference/'; + fs.readdir(baseDir, (err, files) => { + files = files.filter(f => f.indexOf('.errors.txt') > 0); + let tasks: Array<(callback: () => void) => void> = []; + files.forEach(f => tasks.push(done => { + fs.readFile(baseDir + f, 'utf-8', (err, baseline) => { + if (err) throw err; - done(); - }); - })); + let g: string[]; + while (g = errRegex.exec(baseline)) { + var errCode = +g[1]; + let msg = keys.filter(k => messages[k].code === errCode)[0]; + messages[msg]['seen'] = true; + } - async.parallelLimit(tasks, 25, done => { - console.log('== List of errors not present in baselines =='); - let count = 0; - for (let k of keys) { - if (messages[k]['seen'] !== true) { - console.log(k); - count++; - } - } - console.log(count + ' of ' + keys.length + ' errors are not in baselines'); - }); - }); + done(); + }); + })); + + async.parallelLimit(tasks, 25, done => { + console.log('== List of errors not present in baselines =='); + let count = 0; + for (let k of keys) { + if (messages[k]['seen'] !== true) { + console.log(k); + count++; + } + } + console.log(count + ' of ' + keys.length + ' errors are not in baselines'); + }); + }); }); fs.readFile('src/compiler/diagnosticInformationMap.generated.ts', 'utf-8', (err, data) => { - let errorRegexp = /\s(\w+): \{ code/g; - let errorNames: string[] = []; - let errMatch: string[]; - while (errMatch = errorRegexp.exec(data)) { - errorNames.push(errMatch[1]); - } + let errorRegexp = /\s(\w+): \{ code/g; + let errorNames: string[] = []; + let errMatch: string[]; + while (errMatch = errorRegexp.exec(data)) { + errorNames.push(errMatch[1]); + } - let allSrc: string = ''; - glob('./src/**/*.ts', {}, (err, files) => { - console.log('Reading ' + files.length + ' source files'); - for(let file of files) { - if (file.indexOf('diagnosticInformationMap.generated.ts') > 0) { - continue; - } + let allSrc: string = ''; + glob('./src/**/*.ts', {}, (err, files) => { + console.log('Reading ' + files.length + ' source files'); + for (let file of files) { + if (file.indexOf('diagnosticInformationMap.generated.ts') > 0) { + continue; + } - let src = fs.readFileSync(file, 'utf-8'); - allSrc = allSrc + src; - } + let src = fs.readFileSync(file, 'utf-8'); + allSrc = allSrc + src; + } - console.log('Consumed ' + allSrc.length + ' characters of source'); + console.log('Consumed ' + allSrc.length + ' characters of source'); - let count = 0; - console.log('== List of errors not used in source ==') - for(let errName of errorNames) { - if (allSrc.indexOf(errName) < 0) { - console.log(errName); - count++; - } - } - console.log(count + ' of ' + errorNames.length + ' errors are not used in source'); - }); + let count = 0; + console.log('== List of errors not used in source ==') + for (let errName of errorNames) { + if (allSrc.indexOf(errName) < 0) { + console.log(errName); + count++; + } + } + console.log(count + ' of ' + errorNames.length + ' errors are not used in source'); + }); }); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d3d8ac1bc1b..3ef2c6ada2a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22,6 +22,17 @@ namespace ts { } export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker { + // Cancellation that controls whether or not we can cancel in the middle of type checking. + // In general cancelling is *not* safe for the type checker. We might be in the middle of + // computing something, and we will leave our internals in an inconsistent state. Callers + // who set the cancellation token should catch if a cancellation exception occurs, and + // should throw away and create a new TypeChecker. + // + // Currently we only support setting the cancellation token when getting diagnostics. This + // is because diagnostics can be quite expensive, and we want to allow hosts to bail out if + // they no longer need the information (for example, if the user started editing again). + let cancellationToken: CancellationToken; + let Symbol = objectAllocator.getSymbolConstructor(); let Type = objectAllocator.getTypeConstructor(); let Signature = objectAllocator.getSignatureConstructor(); @@ -140,6 +151,7 @@ namespace ts { let tupleTypes: Map = {}; let unionTypes: Map = {}; + let intersectionTypes: Map = {}; let stringLiteralTypes: Map = {}; let emitExtends = false; let emitDecorate = false; @@ -193,10 +205,10 @@ namespace ts { return checker; - function getEmitResolver(sourceFile?: SourceFile) { + function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) { // Ensure we have all the type information in place for this file so that all the // emitter questions of this resolver will return the right information. - getDiagnostics(sourceFile); + getDiagnostics(sourceFile, cancellationToken); return emitResolver; } @@ -1575,8 +1587,8 @@ namespace ts { else if (type.flags & TypeFlags.Tuple) { writeTupleType(type); } - else if (type.flags & TypeFlags.Union) { - writeUnionType(type, flags); + else if (type.flags & TypeFlags.UnionOrIntersection) { + writeUnionOrIntersectionType(type, flags); } else if (type.flags & TypeFlags.Anonymous) { writeAnonymousType(type, flags); @@ -1595,16 +1607,16 @@ namespace ts { } } - function writeTypeList(types: Type[], union: boolean) { + function writeTypeList(types: Type[], delimiter: SyntaxKind) { for (let i = 0; i < types.length; i++) { if (i > 0) { - if (union) { + if (delimiter !== SyntaxKind.CommaToken) { writeSpace(writer); } - writePunctuation(writer, union ? SyntaxKind.BarToken : SyntaxKind.CommaToken); + writePunctuation(writer, delimiter); writeSpace(writer); } - writeType(types[i], union ? TypeFormatFlags.InElementType : TypeFormatFlags.None); + writeType(types[i], delimiter === SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType); } } @@ -1662,15 +1674,15 @@ namespace ts { function writeTupleType(type: TupleType) { writePunctuation(writer, SyntaxKind.OpenBracketToken); - writeTypeList(type.elementTypes, /*union*/ false); + writeTypeList(type.elementTypes, SyntaxKind.CommaToken); writePunctuation(writer, SyntaxKind.CloseBracketToken); } - function writeUnionType(type: UnionType, flags: TypeFormatFlags) { + function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } - writeTypeList(type.types, /*union*/ true); + writeTypeList(type.types, type.flags & TypeFlags.Union ? SyntaxKind.BarToken : SyntaxKind.AmpersandToken); if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.CloseParenToken); } @@ -1747,7 +1759,7 @@ namespace ts { } function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) { - let resolved = resolveObjectOrUnionTypeMembers(type); + let resolved = resolveStructuredTypeMembers(type); if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) { if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { writePunctuation(writer, SyntaxKind.OpenBraceToken); @@ -2082,6 +2094,7 @@ namespace ts { case SyntaxKind.ArrayType: case SyntaxKind.TupleType: case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: case SyntaxKind.ParenthesizedType: return isDeclarationVisible(node.parent); @@ -2704,7 +2717,7 @@ namespace ts { if (baseConstructorType.flags & TypeFlags.ObjectType) { // Resolving the members of a class requires us to resolve the base class of that class. // We force resolution here such that we catch circularities now. - resolveObjectOrUnionTypeMembers(baseConstructorType); + resolveStructuredTypeMembers(baseConstructorType); } if (!popTypeResolution()) { error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); @@ -3034,7 +3047,7 @@ namespace ts { } function resolveTupleTypeMembers(type: TupleType) { - let arrayType = resolveObjectOrUnionTypeMembers(createArrayType(getUnionType(type.elementTypes))); + let arrayType = resolveStructuredTypeMembers(createArrayType(getUnionType(type.elementTypes))); let members = createTupleTypeMemberSymbols(type.elementTypes); addInheritedMembers(members, arrayType.properties); setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType); @@ -3100,6 +3113,26 @@ namespace ts { setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType); } + function intersectTypes(type1: Type, type2: Type): Type { + return !type1 ? type2 : !type2 ? type1 : getIntersectionType([type1, type2]); + } + + function resolveIntersectionTypeMembers(type: IntersectionType) { + // The members and properties collections are empty for intersection types. To get all properties of an + // intersection type use getPropertiesOfType (only the language service uses this). + let callSignatures: Signature[] = emptyArray; + let constructSignatures: Signature[] = emptyArray; + let stringIndexType: Type = undefined; + let numberIndexType: Type = undefined; + for (let t of type.types) { + callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call)); + constructSignatures = concatenate(constructSignatures, getSignaturesOfType(t, SignatureKind.Construct)); + stringIndexType = intersectTypes(stringIndexType, getIndexTypeOfType(t, IndexKind.String)); + numberIndexType = intersectTypes(numberIndexType, getIndexTypeOfType(t, IndexKind.Number)); + } + setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType); + } + function resolveAnonymousTypeMembers(type: ObjectType) { let symbol = type.symbol; let members: SymbolTable; @@ -3144,7 +3177,7 @@ namespace ts { setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType); } - function resolveObjectOrUnionTypeMembers(type: ObjectType): ResolvedType { + function resolveStructuredTypeMembers(type: ObjectType): ResolvedType { if (!(type).members) { if (type.flags & (TypeFlags.Class | TypeFlags.Interface)) { resolveClassOrInterfaceMembers(type); @@ -3158,6 +3191,9 @@ namespace ts { else if (type.flags & TypeFlags.Union) { resolveUnionTypeMembers(type); } + else if (type.flags & TypeFlags.Intersection) { + resolveIntersectionTypeMembers(type); + } else { resolveTypeReferenceMembers(type); } @@ -3168,16 +3204,16 @@ namespace ts { // Return properties of an object type or an empty array for other types function getPropertiesOfObjectType(type: Type): Symbol[] { if (type.flags & TypeFlags.ObjectType) { - return resolveObjectOrUnionTypeMembers(type).properties; + return resolveStructuredTypeMembers(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. + // 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) { - let resolved = resolveObjectOrUnionTypeMembers(type); + let resolved = resolveStructuredTypeMembers(type); if (hasProperty(resolved.members, name)) { let symbol = resolved.members[name]; if (symbolIsValue(symbol)) { @@ -3187,20 +3223,23 @@ namespace ts { } } - function getPropertiesOfUnionType(type: UnionType): Symbol[] { - let result: Symbol[] = []; - forEach(getPropertiesOfType(type.types[0]), prop => { - let unionProp = getPropertyOfUnionType(type, prop.name); - if (unionProp) { - result.push(unionProp); + function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] { + for (let current of type.types) { + for (let prop of getPropertiesOfType(current)) { + getPropertyOfUnionOrIntersectionType(type, prop.name); } - }); - return result; + // The properties of a union type are those that are present in all constituent types, so + // we only need to check the properties of the first type + if (type.flags & TypeFlags.Union) { + break; + } + } + return type.resolvedProperties ? symbolsToArray(type.resolvedProperties) : emptyArray; } function getPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); - return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(type) : getPropertiesOfObjectType(type); + return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(type) : getPropertiesOfObjectType(type); } /** @@ -3235,24 +3274,33 @@ namespace ts { return type; } - function createUnionProperty(unionType: UnionType, name: string): Symbol { - let types = unionType.types; + function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol { + let types = containingType.types; let props: Symbol[]; for (let current of types) { let type = getApparentType(current); if (type !== unknownType) { let prop = getPropertyOfType(type, name); - if (!prop || getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected)) { + if (prop && !(getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected))) { + if (!props) { + props = [prop]; + } + else if (!contains(props, prop)) { + props.push(prop); + } + } + else if (containingType.flags & TypeFlags.Union) { + // A union type requires the property to be present in all constituent types return undefined; } - if (!props) { - props = [prop]; - } - else { - props.push(prop); - } } } + if (!props) { + return undefined; + } + if (props.length === 1) { + return props[0]; + } let propTypes: Type[] = []; let declarations: Declaration[] = []; for (let prop of props) { @@ -3261,19 +3309,19 @@ namespace ts { } propTypes.push(getTypeOfSymbol(prop)); } - let result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.UnionProperty, name); - result.unionType = unionType; + let result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty, name); + result.containingType = containingType; result.declarations = declarations; - result.type = getUnionType(propTypes); + result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes); return result; } - function getPropertyOfUnionType(type: UnionType, name: string): Symbol { + function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol { let properties = type.resolvedProperties || (type.resolvedProperties = {}); if (hasProperty(properties, name)) { return properties[name]; } - let property = createUnionProperty(type, name); + let property = createUnionOrIntersectionProperty(type, name); if (property) { properties[name] = property; } @@ -3286,7 +3334,7 @@ namespace ts { function getPropertyOfType(type: Type, name: string): Symbol { type = getApparentType(type); if (type.flags & TypeFlags.ObjectType) { - let resolved = resolveObjectOrUnionTypeMembers(type); + let resolved = resolveStructuredTypeMembers(type); if (hasProperty(resolved.members, name)) { let symbol = resolved.members[name]; if (symbolIsValue(symbol)) { @@ -3301,15 +3349,15 @@ namespace ts { } return getPropertyOfObjectType(globalObjectType, name); } - if (type.flags & TypeFlags.Union) { - return getPropertyOfUnionType(type, name); + if (type.flags & TypeFlags.UnionOrIntersection) { + return getPropertyOfUnionOrIntersectionType(type, name); } return undefined; } - function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] { - if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) { - let resolved = resolveObjectOrUnionTypeMembers(type); + function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): Signature[] { + if (type.flags & TypeFlags.StructuredType) { + let resolved = resolveStructuredTypeMembers(type); return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures; } return emptyArray; @@ -3318,22 +3366,21 @@ namespace ts { // Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and // maps primitive types and type parameters are to their apparent types. function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] { - return getSignaturesOfObjectOrUnionType(getApparentType(type), kind); + return getSignaturesOfStructuredType(getApparentType(type), kind); } function typeHasCallOrConstructSignatures(type: Type): boolean { let apparentType = getApparentType(type); - if (apparentType.flags & (TypeFlags.ObjectType | TypeFlags.Union)) { - let resolved = resolveObjectOrUnionTypeMembers(type); - return resolved.callSignatures.length > 0 - || resolved.constructSignatures.length > 0; + if (apparentType.flags & TypeFlags.StructuredType) { + let resolved = resolveStructuredTypeMembers(type); + return resolved.callSignatures.length > 0 || resolved.constructSignatures.length > 0; } return false; } - function getIndexTypeOfObjectOrUnionType(type: Type, kind: IndexKind): Type { - if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) { - let resolved = resolveObjectOrUnionTypeMembers(type); + function getIndexTypeOfStructuredType(type: Type, kind: IndexKind): Type { + if (type.flags & TypeFlags.StructuredType) { + let resolved = resolveStructuredTypeMembers(type); return kind === IndexKind.String ? resolved.stringIndexType : resolved.numberIndexType; } } @@ -3341,7 +3388,7 @@ namespace ts { // Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and // maps primitive types and type parameters are to their apparent types. function getIndexTypeOfType(type: Type, kind: IndexKind): Type { - return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind); + return getIndexTypeOfStructuredType(getApparentType(type), kind); } // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual @@ -3891,25 +3938,20 @@ namespace ts { return links.resolvedType; } - function addTypeToSortedSet(sortedSet: Type[], type: Type) { - if (type.flags & TypeFlags.Union) { - addTypesToSortedSet(sortedSet, (type).types); + function addTypeToSet(typeSet: Type[], type: Type, typeSetKind: TypeFlags) { + if (type.flags & typeSetKind) { + addTypesToSet(typeSet, (type).types, typeSetKind); } - else { - let i = 0; - let id = type.id; - while (i < sortedSet.length && sortedSet[i].id < id) { - i++; - } - if (i === sortedSet.length || sortedSet[i].id !== id) { - sortedSet.splice(i, 0, type); - } + else if (!contains(typeSet, type)) { + typeSet.push(type); } } - function addTypesToSortedSet(sortedTypes: Type[], types: Type[]) { + // Add the given types to the given type set. Order is preserved, duplicates are removed, + // and nested types of the given kind are flattened into the set. + function addTypesToSet(typeSet: Type[], types: Type[], typeSetKind: TypeFlags) { for (let type of types) { - addTypeToSortedSet(sortedTypes, type); + addTypeToSet(typeSet, type, typeSetKind); } } @@ -3951,6 +3993,10 @@ namespace ts { } } + function compareTypeIds(type1: Type, type2: Type): number { + return type1.id - type2.id; + } + // The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag // is true when creating a union type from a type node and when instantiating a union type. In both of those // cases subtype reduction has to be deferred to properly support recursive union types. For example, a @@ -3959,26 +4005,27 @@ namespace ts { if (types.length === 0) { return emptyObjectType; } - let sortedTypes: Type[] = []; - addTypesToSortedSet(sortedTypes, types); + let typeSet: Type[] = []; + addTypesToSet(typeSet, types, TypeFlags.Union); + typeSet.sort(compareTypeIds); if (noSubtypeReduction) { - if (containsTypeAny(sortedTypes)) { + if (containsTypeAny(typeSet)) { return anyType; } - removeAllButLast(sortedTypes, undefinedType); - removeAllButLast(sortedTypes, nullType); + removeAllButLast(typeSet, undefinedType); + removeAllButLast(typeSet, nullType); } else { - removeSubtypes(sortedTypes); + removeSubtypes(typeSet); } - if (sortedTypes.length === 1) { - return sortedTypes[0]; + if (typeSet.length === 1) { + return typeSet[0]; } - let id = getTypeListId(sortedTypes); + let id = getTypeListId(typeSet); let type = unionTypes[id]; if (!type) { - type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes)); - type.types = sortedTypes; + type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(typeSet)); + type.types = typeSet; type.reducedType = noSubtypeReduction ? undefined : type; } return type; @@ -4010,6 +4057,40 @@ namespace ts { return links.resolvedType; } + // We do not perform supertype reduction on intersection types. Intersection types are created only by the & + // type operator and we can't reduce those because we want to support recursive intersection types. For example, + // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. + // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution + // for intersections of types with signatures can be deterministic. + function getIntersectionType(types: Type[]): Type { + if (types.length === 0) { + return emptyObjectType; + } + let typeSet: Type[] = []; + addTypesToSet(typeSet, types, TypeFlags.Intersection); + if (containsTypeAny(typeSet)) { + return anyType; + } + if (typeSet.length === 1) { + return typeSet[0]; + } + let id = getTypeListId(typeSet); + let type = intersectionTypes[id]; + if (!type) { + type = intersectionTypes[id] = createObjectType(TypeFlags.Intersection | getWideningFlagsOfTypes(typeSet)); + type.types = typeSet; + } + return type; + } + + function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { + let links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode)); + } + return links.resolvedType; + } + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type { let links = getNodeLinks(node); if (!links.resolvedType) { @@ -4067,6 +4148,8 @@ namespace ts { return getTypeFromTupleTypeNode(node); case SyntaxKind.UnionType: return getTypeFromUnionTypeNode(node); + case SyntaxKind.IntersectionType: + return getTypeFromIntersectionTypeNode(node); case SyntaxKind.ParenthesizedType: return getTypeFromTypeNode((node).type); case SyntaxKind.FunctionType: @@ -4254,6 +4337,9 @@ namespace ts { if (type.flags & TypeFlags.Union) { return getUnionType(instantiateList((type).types, mapper, instantiateType), /*noSubtypeReduction*/ true); } + if (type.flags & TypeFlags.Intersection) { + return getIntersectionType(instantiateList((type).types, mapper, instantiateType)); + } } return type; } @@ -4294,7 +4380,7 @@ namespace ts { function getTypeWithoutSignatures(type: Type): Type { if (type.flags & TypeFlags.ObjectType) { - let resolved = resolveObjectOrUnionTypeMembers(type); + let resolved = resolveStructuredTypeMembers(type); if (resolved.constructSignatures.length) { let result = createObjectType(TypeFlags.Anonymous, type.symbol); result.members = resolved.members; @@ -4414,37 +4500,10 @@ namespace ts { } } let saveErrorInfo = errorInfo; - if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) { - if (relation === identityRelation) { - if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) { - if (result = unionTypeRelatedToUnionType(source, target)) { - if (result &= unionTypeRelatedToUnionType(target, source)) { - return result; - } - } - } - else if (source.flags & TypeFlags.Union) { - if (result = unionTypeRelatedToType(source, target, reportErrors)) { - return result; - } - } - else { - if (result = unionTypeRelatedToType(target, source, reportErrors)) { - return result; - } - } - } - else { - if (source.flags & TypeFlags.Union) { - if (result = unionTypeRelatedToType(source, target, reportErrors)) { - return result; - } - } - else { - if (result = typeRelatedToUnionType(source, target, reportErrors)) { - return result; - } - } + if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { + // We have type references to same target type, see if relationship holds for all type arguments + if (result = typesRelatedTo((source).typeArguments, (target).typeArguments, reportErrors)) { + return result; } } else if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) { @@ -4452,10 +4511,43 @@ namespace ts { return result; } } - else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { - // We have type references to same target type, see if relationship holds for all type arguments - if (result = typesRelatedTo((source).typeArguments, (target).typeArguments, reportErrors)) { - return result; + else if (relation !== identityRelation) { + // Note that the "each" checks must precede the "some" checks to produce the correct results + if (source.flags & TypeFlags.Union) { + if (result = eachTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else if (target.flags & TypeFlags.Intersection) { + if (result = typeRelatedToEachType(source, target, reportErrors)) { + return result; + } + } + else { + // It is necessary to try "each" checks on both sides because there may be nested "some" checks + // on either side that need to be prioritized. For example, A | B = (A | B) & (C | D) or + // A & B = (A & B) | (C & D). + if (source.flags & TypeFlags.Intersection) { + // If target is a union type the following check will report errors so we suppress them here + if (result = someTypeRelatedToType(source, target, reportErrors && !(target.flags & TypeFlags.Union))) { + return result; + } + } + if (target.flags & TypeFlags.Union) { + if (result = typeRelatedToSomeType(source, target, reportErrors)) { + return result; + } + } + } + } + else { + if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union || + source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) { + if (result = eachTypeRelatedToSomeType(source, target)) { + if (result &= eachTypeRelatedToSomeType(target, source)) { + return result; + } + } } } @@ -4463,17 +4555,20 @@ namespace ts { // it may hold in a structural comparison. // Report structural errors only if we haven't reported any errors yet let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; - // identity relation does not use apparent type + // Identity relation does not use apparent type let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source); - if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { + // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates + // to X. Failing both of those we want to check if the aggregation of A and B's members structurally + // relates to X. Thus, we include intersection types on the source side here. + if (sourceOrApparentType.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) { if (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { errorInfo = saveErrorInfo; return result; } } - else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { + else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.UnionOrIntersection) { // We clear the errors first because the following check often gives a better error than - // the union comparison above if it is applicable. + // the union or intersection comparison above if it is applicable. errorInfo = saveErrorInfo; if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) { return result; @@ -4493,11 +4588,11 @@ namespace ts { return Ternary.False; } - function unionTypeRelatedToUnionType(source: UnionType, target: UnionType): Ternary { + function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary { let result = Ternary.True; let sourceTypes = source.types; for (let sourceType of sourceTypes) { - let related = typeRelatedToUnionType(sourceType, target, false); + let related = typeRelatedToSomeType(sourceType, target, false); if (!related) { return Ternary.False; } @@ -4506,7 +4601,7 @@ namespace ts { return result; } - function typeRelatedToUnionType(source: Type, target: UnionType, reportErrors: boolean): Ternary { + function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { let targetTypes = target.types; for (let i = 0, len = targetTypes.length; i < len; i++) { let related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1); @@ -4517,7 +4612,31 @@ namespace ts { return Ternary.False; } - function unionTypeRelatedToType(source: UnionType, target: Type, reportErrors: boolean): Ternary { + function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { + let result = Ternary.True; + let targetTypes = target.types; + for (let targetType of targetTypes) { + let related = isRelatedTo(source, targetType, reportErrors); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + + function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { + let sourceTypes = source.types; + for (let i = 0, len = sourceTypes.length; i < len; i++) { + let related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1); + if (related) { + return related; + } + } + return Ternary.False; + } + + function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { let result = Ternary.True; let sourceTypes = source.types; for (let sourceType of sourceTypes) { @@ -4572,7 +4691,7 @@ namespace ts { // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion // and issue an error. Otherwise, actually compare the structure of the two types. - function objectTypeRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + function objectTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { if (overflow) { return Ternary.False; } @@ -4647,7 +4766,7 @@ namespace ts { return result; } - function propertiesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { if (relation === identityRelation) { return propertiesIdenticalTo(source, target); } @@ -4731,7 +4850,10 @@ namespace ts { return result; } - function propertiesIdenticalTo(source: ObjectType, target: ObjectType): Ternary { + function propertiesIdenticalTo(source: Type, target: Type): Ternary { + if (!(source.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType)) { + return Ternary.False; + } let sourceProperties = getPropertiesOfObjectType(source); let targetProperties = getPropertiesOfObjectType(target); if (sourceProperties.length !== targetProperties.length) { @@ -4752,7 +4874,7 @@ namespace ts { return result; } - function signaturesRelatedTo(source: ObjectType, target: ObjectType, kind: SignatureKind, reportErrors: boolean): Ternary { + function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean): Ternary { if (relation === identityRelation) { return signaturesIdenticalTo(source, target, kind); } @@ -4878,7 +5000,7 @@ namespace ts { return result & isRelatedTo(s, t, reportErrors); } - function signaturesIdenticalTo(source: ObjectType, target: ObjectType, kind: SignatureKind): Ternary { + function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { let sourceSignatures = getSignaturesOfType(source, kind); let targetSignatures = getSignaturesOfType(target, kind); if (sourceSignatures.length !== targetSignatures.length) { @@ -4895,7 +5017,7 @@ namespace ts { return result; } - function stringIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + function stringIndexTypesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { if (relation === identityRelation) { return indexTypesIdenticalTo(IndexKind.String, source, target); } @@ -4920,7 +5042,7 @@ namespace ts { return Ternary.True; } - function numberIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { + function numberIndexTypesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { if (relation === identityRelation) { return indexTypesIdenticalTo(IndexKind.Number, source, target); } @@ -4953,7 +5075,7 @@ namespace ts { return Ternary.True; } - function indexTypesIdenticalTo(indexKind: IndexKind, source: ObjectType, target: ObjectType): Ternary { + function indexTypesIdenticalTo(indexKind: IndexKind, source: Type, target: Type): Ternary { let targetType = getIndexTypeOfType(target, indexKind); let sourceType = getIndexTypeOfType(source, indexKind); if (!sourceType && !targetType) { @@ -5337,11 +5459,11 @@ namespace ts { inferFromTypes(sourceTypes[i], targetTypes[i]); } } - else if (target.flags & TypeFlags.Union) { - let targetTypes = (target).types; + else if (target.flags & TypeFlags.UnionOrIntersection) { + let targetTypes = (target).types; let typeParameterCount = 0; let typeParameter: TypeParameter; - // First infer to each type in union that isn't a type parameter + // First infer to each type in union or intersection that isn't a type parameter for (let t of targetTypes) { if (t.flags & TypeFlags.TypeParameter && contains(context.typeParameters, t)) { typeParameter = t; @@ -5351,16 +5473,19 @@ namespace ts { inferFromTypes(source, t); } } - // If union contains a single naked type parameter, make a secondary inference to that type parameter - if (typeParameterCount === 1) { + // Next, if target is a union type containing a single naked type parameter, make a + // secondary inference to that type parameter. We don't do this for intersection types + // because in a target type like Foo & T we don't know how which parts of the source type + // should be matched by Foo and which should be inferred to T. + if (target.flags & TypeFlags.Union && typeParameterCount === 1) { inferiority++; inferFromTypes(source, typeParameter); inferiority--; } } - else if (source.flags & TypeFlags.Union) { - // Source is a union type, infer from each consituent type - let sourceTypes = (source).types; + else if (source.flags & TypeFlags.UnionOrIntersection) { + // Source is a union or intersection type, infer from each consituent type + let sourceTypes = (source).types; for (let sourceType of sourceTypes) { inferFromTypes(sourceType, target); } @@ -6343,13 +6468,13 @@ namespace ts { function getTypeOfPropertyOfContextualType(type: Type, name: string) { return applyToContextualType(type, t => { - let prop = getPropertyOfObjectType(t, name); + let prop = t.flags & TypeFlags.StructuredType ? getPropertyOfType(t, name) : undefined; return prop ? getTypeOfSymbol(prop) : undefined; }); } function getIndexTypeOfContextualType(type: Type, kind: IndexKind) { - return applyToContextualType(type, t => getIndexTypeOfObjectOrUnionType(t, kind)); + return applyToContextualType(type, t => getIndexTypeOfStructuredType(t, kind)); } // Return true if the given contextual type is a tuple-like type @@ -6359,7 +6484,7 @@ namespace ts { // 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((type).types, t => getIndexTypeOfObjectOrUnionType(t, kind)) : getIndexTypeOfObjectOrUnionType(type, kind)); + return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => getIndexTypeOfStructuredType(t, kind)) : getIndexTypeOfStructuredType(type, kind)); } // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of @@ -6442,6 +6567,11 @@ namespace ts { // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. function getContextualType(node: Expression): Type { + let type = getContextualTypeWorker(node); + return type && getApparentType(type); + } + + function getContextualTypeWorker(node: Expression): Type { if (isInsideWithStatementBody(node)) { // We cannot answer semantic questions within a with block, do not proceed any further return undefined; @@ -6491,7 +6621,7 @@ namespace ts { // 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 { - let signatures = getSignaturesOfObjectOrUnionType(type, SignatureKind.Call); + let signatures = getSignaturesOfStructuredType(type, SignatureKind.Call); if (signatures.length === 1) { let signature = signatures[0]; if (!signature.typeParameters) { @@ -6533,7 +6663,7 @@ namespace ts { // The signature set of all constituent type with call signatures should match // So number of signatures allowed is either 0 or 1 if (signatureList && - getSignaturesOfObjectOrUnionType(current, SignatureKind.Call).length > 1) { + getSignaturesOfStructuredType(current, SignatureKind.Call).length > 1) { return undefined; } @@ -7686,7 +7816,7 @@ namespace 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) { - let resolved = resolveObjectOrUnionTypeMembers(type); + let resolved = resolveStructuredTypeMembers(type); if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 && resolved.properties.length === 0 && !resolved.stringIndexType && !resolved.numberIndexType) { return resolved.callSignatures[0]; @@ -9126,8 +9256,8 @@ namespace ts { if (type.flags & kind) { return true; } - if (type.flags & TypeFlags.Union) { - let types = (type).types; + if (type.flags & TypeFlags.UnionOrIntersection) { + let types = (type).types; for (let current of types) { if (current.flags & kind) { return true; @@ -9138,13 +9268,13 @@ namespace ts { return false; } - // Return true if type has the given flags, or is a union type composed of types that all have those flags. + // Return true if type has the given flags, or is a union or intersection type composed of types that all have those flags. function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { if (type.flags & kind) { return true; } - if (type.flags & TypeFlags.Union) { - let types = (type).types; + if (type.flags & TypeFlags.UnionOrIntersection) { + let types = (type).types; for (let current of types) { if (!(current.flags & kind)) { return false; @@ -10169,7 +10299,7 @@ namespace ts { forEach(node.elementTypes, checkSourceElement); } - function checkUnionType(node: UnionTypeNode) { + function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) { forEach(node.types, checkSourceElement); } @@ -12909,8 +13039,24 @@ namespace ts { } function checkSourceElement(node: Node): void { - if (!node) return; - switch (node.kind) { + if (!node) { + return; + } + + let kind = node.kind; + if (cancellationToken) { + // Only bother checking on a few construct kinds. We don't want to be excessivly + // hitting the cancellation token on every node we check. + switch (kind) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + cancellationToken.throwIfCancellationRequested(); + } + } + + switch (kind) { case SyntaxKind.TypeParameter: return checkTypeParameter(node); case SyntaxKind.Parameter: @@ -12946,7 +13092,8 @@ namespace ts { case SyntaxKind.TupleType: return checkTupleType(node); case SyntaxKind.UnionType: - return checkUnionType(node); + case SyntaxKind.IntersectionType: + return checkUnionOrIntersectionType(node); case SyntaxKind.ParenthesizedType: return checkSourceElement((node).type); case SyntaxKind.FunctionDeclaration: @@ -13185,7 +13332,20 @@ namespace ts { } } - function getDiagnostics(sourceFile?: SourceFile): Diagnostic[] { + function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken): Diagnostic[] { + try { + // Record the cancellation token so it can be checked later on during checkSourceElement. + // Do this in a finally block so we can ensure that it gets reset back to nothing after + // this call is done. + cancellationToken = ct; + return getDiagnosticsWorker(sourceFile); + } + finally { + cancellationToken = undefined; + } + } + + function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] { throwIfNonDiagnosticsProducing(); if (sourceFile) { checkSourceFile(sourceFile); @@ -13588,10 +13748,10 @@ namespace ts { } function getRootSymbols(symbol: Symbol): Symbol[] { - if (symbol.flags & SymbolFlags.UnionProperty) { + if (symbol.flags & SymbolFlags.SyntheticProperty) { let symbols: Symbol[] = []; let name = symbol.name; - forEach(getSymbolLinks(symbol).unionType.types, t => { + forEach(getSymbolLinks(symbol).containingType.types, t => { symbols.push(getPropertyOfType(t, name)); }); return symbols; @@ -13888,6 +14048,7 @@ namespace ts { case SyntaxKind.TypeQuery: case SyntaxKind.TypeLiteral: case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: case SyntaxKind.AnyKeyword: break; default: diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 823349eda91..427084b5779 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -805,4 +805,4 @@ namespace ts { Debug.assert(false, message); } } -} +} diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index f721f46e478..35e2c6ed295 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -342,6 +342,8 @@ namespace ts { return emitTupleType(type); case SyntaxKind.UnionType: return emitUnionType(type); + case SyntaxKind.IntersectionType: + return emitIntersectionType(type); case SyntaxKind.ParenthesizedType: return emitParenType(type); case SyntaxKind.FunctionType: @@ -424,6 +426,10 @@ namespace ts { emitSeparatedList(type.types, " | ", emitType); } + function emitIntersectionType(type: IntersectionTypeNode) { + emitSeparatedList(type.types, " & ", emitType); + } + function emitParenType(type: ParenthesizedTypeNode) { write("("); emitType(type.type); diff --git a/src/compiler/factory.generated.ts b/src/compiler/factory.generated.ts index 291e04ea4de..d1b23fcbe7b 100644 --- a/src/compiler/factory.generated.ts +++ b/src/compiler/factory.generated.ts @@ -461,6 +461,18 @@ namespace ts { } return node; } + export function createIntersectionType(types?: Array): IntersectionTypeNode { + let node = createNode(SyntaxKind.IntersectionType); + node.types = types && createNodeArray(types) + return node; + } + export function updateIntersectionType(node: IntersectionTypeNode, types: Array): IntersectionTypeNode { + if (types !== node.types) { + let newNode = createIntersectionType(types); + return updateFrom(node, newNode); + } + return node; + } export function createParenthesizedType(type?: TypeNode): ParenthesizedTypeNode { let node = createNode(SyntaxKind.ParenthesizedType); node.type = type; @@ -2161,6 +2173,9 @@ namespace ts { export function isUnionType(node: Node): node is UnionTypeNode { return node && node.kind === SyntaxKind.UnionType; } + export function isIntersectionType(node: Node): node is IntersectionTypeNode { + return node && node.kind === SyntaxKind.IntersectionType; + } export function isParenthesizedType(node: Node): node is ParenthesizedTypeNode { return node && node.kind === SyntaxKind.ParenthesizedType; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a01e55f54dd..f6b7f0fdeed 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -107,7 +107,8 @@ namespace ts { case SyntaxKind.TupleType: return visitNodes(cbNodes, (node).elementTypes); case SyntaxKind.UnionType: - return visitNodes(cbNodes, (node).types); + case SyntaxKind.IntersectionType: + return visitNodes(cbNodes, (node).types); case SyntaxKind.ParenthesizedType: return visitNode(cbNode, (node).type); case SyntaxKind.ObjectBindingPattern: @@ -1236,6 +1237,11 @@ namespace ts { return isIdentifier(); } + function nextTokenIsIdentifierOrKeyword() { + nextToken(); + return isIdentifierOrKeyword(); + } + function isHeritageClauseExtendsOrImplementsKeyword(): boolean { if (token === SyntaxKind.ImplementsKeyword || token === SyntaxKind.ExtendsKeyword) { @@ -1970,8 +1976,8 @@ namespace ts { function parseParameter(): ParameterDeclaration { let node = beginNode(factory.createParameter()); node.decorators = parseDecorators(); - node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); setModifiers(node, parseModifiers()); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); // FormalParameter [Yield,Await]: // BindingElement[?Yield,?Await] @@ -2392,22 +2398,30 @@ namespace ts { return type; } - function parseUnionTypeOrHigher(): TypeNode { - let type = parseArrayTypeOrHigher(); - if (token === SyntaxKind.BarToken) { + function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode { + let type = parseConstituentType(); + if (token === operator) { let types = >[type]; types.pos = type.pos; - while (parseOptional(SyntaxKind.BarToken)) { - types.push(parseArrayTypeOrHigher()); + while (parseOptional(operator)) { + types.push(parseConstituentType()); } types.end = getNodeEnd(); - let node = beginNode(factory.createUnionType(), type.pos); + let node = beginNode(factory.createNode(kind), type.pos); node.types = types; type = finishNode(node); } return type; } + function parseIntersectionTypeOrHigher(): TypeNode { + return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseArrayTypeOrHigher, SyntaxKind.AmpersandToken); + } + + function parseUnionTypeOrHigher(): TypeNode { + return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken); + } + function isStartOfFunctionType(): boolean { if (token === SyntaxKind.LessThanToken) { return true; @@ -3152,7 +3166,7 @@ namespace ts { if (sourceFile.languageVariant !== LanguageVariant.JSX) { return parseTypeAssertion(); } - if(lookAhead(nextTokenIsIdentifier)) { + if(lookAhead(nextTokenIsIdentifierOrKeyword)) { return parseJsxElementOrSelfClosingElement(); } // Fall through @@ -3370,7 +3384,7 @@ namespace ts { function parseJsxElementName(): EntityName { scanJsxIdentifier(); - let elementName: EntityName = parseIdentifier(); + let elementName: EntityName = parseIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { scanJsxIdentifier(); let node = beginNode(factory.createQualifiedName(), elementName.pos); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b9321ab3461..28efaf24cca 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -104,14 +104,14 @@ namespace ts { }; } - export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile): Diagnostic[] { - let diagnostics = program.getOptionsDiagnostics().concat( - program.getSyntacticDiagnostics(sourceFile), - program.getGlobalDiagnostics(), - program.getSemanticDiagnostics(sourceFile)); + export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] { + let diagnostics = program.getOptionsDiagnostics(cancellationToken).concat( + program.getSyntacticDiagnostics(sourceFile, cancellationToken), + program.getGlobalDiagnostics(cancellationToken), + program.getSemanticDiagnostics(sourceFile, cancellationToken)); if (program.getCompilerOptions().declaration) { - diagnostics.concat(program.getDeclarationDiagnostics(sourceFile)); + diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken)); } return sortAndDeduplicateDiagnostics(diagnostics); @@ -233,10 +233,15 @@ namespace ts { return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false)); } - function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback): EmitResult { + function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult { + return runWithCancellationToken(() => emitWorker(this, sourceFile, writeFileCallback, cancellationToken)); + } + + function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken): EmitResult { // If the noEmitOnError flag is set, then check if we have any errors so far. If so, - // immediately bail out. - if (options.noEmitOnError && getPreEmitDiagnostics(this).length > 0) { + // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we + // get any preEmit diagnostics, not just the ones + if (options.noEmitOnError && getPreEmitDiagnostics(program, /*sourceFile:*/ undefined, cancellationToken).length > 0) { return { diagnostics: [], sourceMaps: undefined, emitSkipped: true }; } @@ -265,53 +270,86 @@ namespace ts { return filesByName.get(fileName); } - function getDiagnosticsHelper(sourceFile: SourceFile, getDiagnostics: (sourceFile: SourceFile) => Diagnostic[]): Diagnostic[] { + function getDiagnosticsHelper( + sourceFile: SourceFile, + getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[], + cancellationToken: CancellationToken): Diagnostic[] { if (sourceFile) { - return getDiagnostics(sourceFile); + return getDiagnostics(sourceFile, cancellationToken); } let allDiagnostics: Diagnostic[] = []; forEach(program.getSourceFiles(), sourceFile => { - addRange(allDiagnostics, getDiagnostics(sourceFile)); + if (cancellationToken) { + cancellationToken.throwIfCancellationRequested(); + } + addRange(allDiagnostics, getDiagnostics(sourceFile, cancellationToken)); }); return sortAndDeduplicateDiagnostics(allDiagnostics); } - function getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[] { - return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile); + function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken); } - function getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[] { - return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile); + function getSemanticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken); } - function getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[] { - return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile); + function getDeclarationDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile, cancellationToken); } - function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { + function getSyntacticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { return sourceFile.parseDiagnostics; } - function getSemanticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { - let typeChecker = getDiagnosticsProducingTypeChecker(); + function runWithCancellationToken(func: () => T): T { + try { + return func(); + } + catch (e) { + if (e instanceof OperationCanceledException) { + // We were canceled while performing the operation. Because our type checker + // might be a bad state, we need to throw it away. + // + // Note: we are overly agressive here. We do not actually *have* to throw away + // the "noDiagnosticsTypeChecker". However, for simplicity, i'd like to keep + // the lifetimes of these two TypeCheckers the same. Also, we generally only + // cancel when the user has made a change anyways. And, in that case, we (the + // program instance) will get thrown away anyways. So trying to keep one of + // these type checkers alive doesn't serve much purpose. + noDiagnosticsTypeChecker = undefined; + diagnosticsProducingTypeChecker = undefined; + } - Debug.assert(!!sourceFile.bindDiagnostics); - let bindDiagnostics = sourceFile.bindDiagnostics; - let checkDiagnostics = typeChecker.getDiagnostics(sourceFile); - let programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName); - - return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics); + throw e; + } } - function getDeclarationDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] { - if (!isDeclarationFile(sourceFile)) { - let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile); - // Don't actually write any files since we're just getting diagnostics. - var writeFile: WriteFileCallback = () => { }; - return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); - } + function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + return runWithCancellationToken(() => { + let typeChecker = getDiagnosticsProducingTypeChecker(); + + Debug.assert(!!sourceFile.bindDiagnostics); + let bindDiagnostics = sourceFile.bindDiagnostics; + let checkDiagnostics = typeChecker.getDiagnostics(sourceFile, cancellationToken); + let programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName); + + return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics); + }); + } + + function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + return runWithCancellationToken(() => { + if (!isDeclarationFile(sourceFile)) { + let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken); + // Don't actually write any files since we're just getting diagnostics. + var writeFile: WriteFileCallback = () => { }; + return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); + } + }); } function getOptionsDiagnostics(): Diagnostic[] { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4425616dcf7..1deb52501cb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -191,6 +191,7 @@ namespace ts { ArrayType, TupleType, UnionType, + IntersectionType, ParenthesizedType, // Binding patterns ObjectBindingPattern, @@ -788,11 +789,16 @@ namespace ts { elementTypes: NodeArray; } - // @kind(SyntaxKind.UnionType) - export interface UnionTypeNode extends TypeNode { + export interface UnionOrIntersectionTypeNode extends TypeNode { types: NodeArray; } + // @kind(SyntaxKind.UnionType) + export interface UnionTypeNode extends UnionOrIntersectionTypeNode { } + + // @kind(SyntaxKind.IntersectionType) + export interface IntersectionTypeNode extends UnionOrIntersectionTypeNode { } + // @kind(SyntaxKind.ParenthesizedType) export interface ParenthesizedTypeNode extends TypeNode { type: TypeNode; @@ -1569,6 +1575,15 @@ namespace ts { (fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void): void; } + export class OperationCanceledException { } + + export interface CancellationToken { + isCancellationRequested(): boolean; + + /** @throws OperationCanceledException if isCancellationRequested is true */ + throwIfCancellationRequested(): void; + } + export interface Program extends ScriptReferenceHost { /** * Get a list of files in the program @@ -1585,13 +1600,13 @@ namespace ts { * used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter * will be invoked when writing the JavaScript and declaration files. */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult; + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult; - getOptionsDiagnostics(): Diagnostic[]; - getGlobalDiagnostics(): Diagnostic[]; - getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[]; - getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[]; - getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[]; + getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[]; + getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; + getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; + getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; /** * Gets a type checker that can be used to semantically analyze source fils in the program. @@ -1702,9 +1717,9 @@ namespace ts { getJsxIntrinsicTagNames(): Symbol[]; // Should not be called directly. Should only be accessed through the Program instance. - /* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[]; + /* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; /* @internal */ getGlobalDiagnostics(): Diagnostic[]; - /* @internal */ getEmitResolver(sourceFile?: SourceFile): EmitResolver; + /* @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken): EmitResolver; /* @internal */ getNodeCount(): number; /* @internal */ getIdentifierCount(): number; @@ -1857,7 +1872,7 @@ namespace ts { Merged = 0x02000000, // Merged symbol (created during program binding) Transient = 0x04000000, // Transient symbol (created during type check) Prototype = 0x08000000, // Prototype property (no source representation) - UnionProperty = 0x10000000, // Property in union type + SyntheticProperty = 0x10000000, // Property in union or intersection type Optional = 0x20000000, // Optional property ExportStar = 0x40000000, // Export * declaration @@ -1936,7 +1951,7 @@ namespace ts { instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) mapper?: TypeMapper; // Type mapper for instantiation alias referenced?: boolean; // True if alias symbol has been referenced as a value - unionType?: UnionType; // Containing union type for union property + containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property resolvedExports?: SymbolTable; // Resolved exports of module exportsChecked?: boolean; // True if exports of external module have been checked isNestedRedeclaration?: boolean; // True if symbol is block scoped redeclaration @@ -2005,17 +2020,18 @@ namespace ts { Interface = 0x00000800, // Interface Reference = 0x00001000, // Generic type reference Tuple = 0x00002000, // Tuple - Union = 0x00004000, // Union - Anonymous = 0x00008000, // Anonymous - Instantiated = 0x00010000, // Instantiated anonymous type + Union = 0x00004000, // Union (T | U) + Intersection = 0x00008000, // Intersection (T & U) + Anonymous = 0x00010000, // Anonymous + Instantiated = 0x00020000, // Instantiated anonymous type /* @internal */ - FromSignature = 0x00020000, // Created for signature assignment check - ObjectLiteral = 0x00040000, // Originates in an object literal + FromSignature = 0x00040000, // Created for signature assignment check + ObjectLiteral = 0x00080000, // Originates in an object literal /* @internal */ - ContainsUndefinedOrNull = 0x00080000, // Type is or contains Undefined or Null type + ContainsUndefinedOrNull = 0x00100000, // Type is or contains Undefined or Null type /* @internal */ - ContainsObjectLiteral = 0x00100000, // Type is or contains object literal type - ESSymbol = 0x00200000, // Type of symbol primitive introduced in ES6 + ContainsObjectLiteral = 0x00200000, // Type is or contains object literal type + ESSymbol = 0x00400000, // Type of symbol primitive introduced in ES6 /* @internal */ Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, @@ -2024,6 +2040,8 @@ namespace ts { StringLike = String | StringLiteral, NumberLike = Number | Enum, ObjectType = Class | Interface | Reference | Tuple | Anonymous, + UnionOrIntersection = Union | Intersection, + StructuredType = ObjectType | Union | Intersection, /* @internal */ RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral } @@ -2083,7 +2101,7 @@ namespace ts { baseArrayType: TypeReference; // Array where T is best common type of element types } - export interface UnionType extends Type { + export interface UnionOrIntersectionType extends Type { types: Type[]; // Constituent types /* @internal */ reducedType: Type; // Reduced union type (all subtypes removed) @@ -2091,9 +2109,13 @@ namespace ts { resolvedProperties: SymbolTable; // Cache of resolved properties } + export interface UnionType extends UnionOrIntersectionType { } + + export interface IntersectionType extends UnionOrIntersectionType { } + /* @internal */ - // Resolved object or union type - export interface ResolvedType extends ObjectType, UnionType { + // Resolved object, union, or intersection type + export interface ResolvedType extends ObjectType, UnionOrIntersectionType { members: SymbolTable; // Properties by name properties: Symbol[]; // Properties callSignatures: Signature[]; // Call signatures of type @@ -2450,14 +2472,9 @@ namespace ts { verticalTab = 0x0B, // \v } - export interface CancellationToken { - isCancellationRequested(): boolean; - } - export interface CompilerHost { getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; getDefaultLibFileName(options: CompilerOptions): string; - getCancellationToken? (): CancellationToken; writeFile: WriteFileCallback; getCurrentDirectory(): string; getCanonicalFileName(fileName: string): string; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0717ed68e83..208237b8b64 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -190,14 +190,14 @@ module FourSlash { return "\nMarker: " + currentTestState.lastKnownMarker + "\nChecking: " + msg + "\n\n"; } - export class TestCancellationToken implements ts.CancellationToken { + export class TestCancellationToken implements ts.HostCancellationToken { // 0 - cancelled // >0 - not cancelled // <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled - private static NotCancelled: number = -1; - private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCancelled; - public isCancellationRequested(): boolean { + private static NotCanceled: number = -1; + private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled; + public isCancellationRequested(): boolean { if (this.numberOfCallsBeforeCancellation < 0) { return false; } @@ -216,7 +216,7 @@ module FourSlash { } public resetCancelled(): void { - this.numberOfCallsBeforeCancellation = TestCancellationToken.NotCancelled; + this.numberOfCallsBeforeCancellation = TestCancellationToken.NotCanceled; } } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 8eb77817533..6cb92df5948 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -103,14 +103,11 @@ module Harness.LanguageService { } } - class CancellationToken { - public static None: CancellationToken = new CancellationToken(null); - - constructor(private cancellationToken: ts.CancellationToken) { - } + class DefaultHostCancellationToken implements ts.HostCancellationToken { + public static Instance = new DefaultHostCancellationToken(); public isCancellationRequested() { - return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + return false; } } @@ -124,8 +121,8 @@ module Harness.LanguageService { export class LanguageServiceAdapterHost { protected fileNameToScript: ts.Map = {}; - constructor(protected cancellationToken: ts.CancellationToken = CancellationToken.None, - protected settings = ts.getDefaultCompilerOptions()) { + constructor(protected cancellationToken = DefaultHostCancellationToken.Instance, + protected settings = ts.getDefaultCompilerOptions()) { } public getNewLine(): string { @@ -173,8 +170,8 @@ module Harness.LanguageService { /// Native adapter class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost { - getCompilationSettings(): ts.CompilerOptions { return this.settings; } - getCancellationToken(): ts.CancellationToken { return this.cancellationToken; } + getCompilationSettings() { return this.settings; } + getCancellationToken() { return this.cancellationToken; } getCurrentDirectory(): string { return ""; } getDefaultLibFileName(): string { return ""; } getScriptFileNames(): string[] { return this.getFilenames(); } @@ -194,7 +191,7 @@ module Harness.LanguageService { export class NativeLanugageServiceAdapter implements LanguageServiceAdapter { private host: NativeLanguageServiceHost; - constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) { + constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { this.host = new NativeLanguageServiceHost(cancellationToken, options); } getHost() { return this.host; } @@ -206,7 +203,7 @@ module Harness.LanguageService { /// Shim adapter class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost { private nativeHost: NativeLanguageServiceHost; - constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) { + constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { super(cancellationToken, options); this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options); } @@ -218,7 +215,7 @@ module Harness.LanguageService { positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter { return this.nativeHost.positionToLineAndCharacter(fileName, position); } getCompilationSettings(): string { return JSON.stringify(this.nativeHost.getCompilationSettings()); } - getCancellationToken(): ts.CancellationToken { return this.nativeHost.getCancellationToken(); } + getCancellationToken(): ts.HostCancellationToken { return this.nativeHost.getCancellationToken(); } getCurrentDirectory(): string { return this.nativeHost.getCurrentDirectory(); } getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); } getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); } @@ -399,7 +396,7 @@ module Harness.LanguageService { export class ShimLanugageServiceAdapter implements LanguageServiceAdapter { private host: ShimLanguageServiceHost; private factory: ts.TypeScriptServicesFactory; - constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) { + constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { this.host = new ShimLanguageServiceHost(cancellationToken, options); this.factory = new TypeScript.Services.TypeScriptServicesFactory(); } @@ -446,7 +443,7 @@ module Harness.LanguageService { class SessionClientHost extends NativeLanguageServiceHost implements ts.server.SessionClientHost { private client: ts.server.SessionClient; - constructor(cancellationToken: ts.CancellationToken, settings: ts.CompilerOptions) { + constructor(cancellationToken: ts.HostCancellationToken, settings: ts.CompilerOptions) { super(cancellationToken, settings); } @@ -575,7 +572,7 @@ module Harness.LanguageService { export class ServerLanugageServiceAdapter implements LanguageServiceAdapter { private host: SessionClientHost; private client: ts.server.SessionClient; - constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) { + constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { // This is the main host that tests use to direct tests var clientHost = new SessionClientHost(cancellationToken, options); var client = new ts.server.SessionClient(clientHost); diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index a4cc7ec2ad5..bc506bc22f9 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -2,7 +2,7 @@ namespace ts.NavigateTo { type RawNavigateToItem = { name: string; fileName: string; matchKind: PatternMatchKind; isCaseSensitive: boolean; declaration: Declaration }; - export function getNavigateToItems(program: Program, cancellationToken: CancellationTokenObject, searchValue: string, maxResultCount: number): NavigateToItem[] { + export function getNavigateToItems(program: Program, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number): NavigateToItem[] { let patternMatcher = createPatternMatcher(searchValue); let rawItems: RawNavigateToItem[] = []; diff --git a/src/services/services.ts b/src/services/services.ts index 3efecd68572..19e0873d8b5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -944,6 +944,10 @@ namespace ts { } } + export interface HostCancellationToken { + isCancellationRequested(): boolean; + } + // // Public interface of the host of a language service instance. // @@ -955,7 +959,7 @@ namespace ts { getScriptVersion(fileName: string): string; getScriptSnapshot(fileName: string): IScriptSnapshot; getLocalizedDiagnosticMessages?(): any; - getCancellationToken?(): CancellationToken; + getCancellationToken?(): HostCancellationToken; getCurrentDirectory(): string; getDefaultLibFileName(options: CompilerOptions): string; log? (s: string): void; @@ -1615,26 +1619,6 @@ namespace ts { }; } - export class OperationCanceledException { } - - export class CancellationTokenObject { - - public static None: CancellationTokenObject = new CancellationTokenObject(null) - - constructor(private cancellationToken: CancellationToken) { - } - - public isCancellationRequested() { - return this.cancellationToken && this.cancellationToken.isCancellationRequested(); - } - - public throwIfCancellationRequested(): void { - if (this.isCancellationRequested()) { - throw new OperationCanceledException(); - } - } - } - // Cache host information about scrip Should be refreshed // at each language service public entry point, since we don't know when // set of scripts handled by the host changes. @@ -2401,6 +2385,21 @@ namespace ts { return ScriptElementKind.unknown; } + class CancellationTokenObject implements CancellationToken { + constructor(private cancellationToken: HostCancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + + public throwIfCancellationRequested(): void { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + } + } + export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry()): LanguageService { let syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); let ruleProvider: formatting.RulesProvider; @@ -2605,7 +2604,7 @@ namespace ts { function getSyntacticDiagnostics(fileName: string) { synchronizeHostData(); - return program.getSyntacticDiagnostics(getValidSourceFile(fileName)); + return program.getSyntacticDiagnostics(getValidSourceFile(fileName), cancellationToken); } /** @@ -2627,13 +2626,13 @@ namespace ts { // Only perform the action per file regardless of '-out' flag as LanguageServiceHost is expected to call this function per file. // Therefore only get diagnostics for given file. - let semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile); + let semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile, cancellationToken); if (!program.getCompilerOptions().declaration) { return semanticDiagnostics; } // If '-d' is enabled, check for emitter error. One example of emitter error is export class implements non-export interface - let declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile); + let declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile, cancellationToken); return concatenate(semanticDiagnostics, declarationDiagnostics); } @@ -2796,7 +2795,8 @@ namespace ts { function getCompilerOptionsDiagnostics() { synchronizeHostData(); - return program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics()); + return program.getOptionsDiagnostics(cancellationToken).concat( + program.getGlobalDiagnostics(cancellationToken)); } /// Completion @@ -3013,21 +3013,30 @@ namespace ts { let objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken); let jsxContainer = tryGetContainingJsxElement(contextToken); if (objectLikeContainer) { - // Object literal expression, look up possible property names from contextual type + // We're looking up possible property names from contextual/inferred/declared type. isMemberCompletion = true; - isNewIdentifierLocation = true; let typeForObject: Type; let existingMembers: Declaration[]; if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) { + // We are completing on contextual types, but may also include properties + // other than those within the declared type. + isNewIdentifierLocation = true; + typeForObject = typeChecker.getContextualType(objectLikeContainer); existingMembers = (objectLikeContainer).properties; } - else { + else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) { + // We are *only* completing on properties from the type being destructured. + isNewIdentifierLocation = false; + typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); existingMembers = (objectLikeContainer).elements; } + else { + Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind); + } if (!typeForObject) { return false; @@ -3689,7 +3698,7 @@ namespace ts { if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; if (flags & SymbolFlags.Property) { - if (flags & SymbolFlags.UnionProperty) { + if (flags & SymbolFlags.SyntheticProperty) { // If union property is result of union of non method (property/accessors/variables), it is labeled as property let unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { let rootSymbolFlags = rootSymbol.getFlags(); @@ -5159,7 +5168,7 @@ namespace ts { // if this symbol is visible from its parent container, e.g. exported, then bail out // if symbol correspond to the union property - bail out - if (symbol.parent || (symbol.flags & SymbolFlags.UnionProperty)) { + if (symbol.parent || (symbol.flags & SymbolFlags.SyntheticProperty)) { return undefined; } @@ -5816,7 +5825,7 @@ namespace ts { }); } - let emitOutput = program.emit(sourceFile, writeFile); + let emitOutput = program.emit(sourceFile, writeFile, cancellationToken); return { outputFiles, @@ -6064,6 +6073,26 @@ namespace ts { return convertClassifications(getEncodedSemanticClassifications(fileName, span)); } + function checkForClassificationCancellation(kind: SyntaxKind) { + // We don't want to actually call back into our host on every node to find out if we've + // been canceled. That would be an enormous amount of chattyness, along with the all + // the overhead of marshalling the data to/from the host. So instead we pick a few + // reasonable node kinds to bother checking on. These node kinds represent high level + // constructs that we would expect to see commonly, but just at a far less frequent + // interval. + // + // For example, in checker.ts (around 750k) we only have around 600 of these constructs. + // That means we're calling back into the host around every 1.2k of the file we process. + // Lib.d.ts has similar numbers. + switch (kind) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + cancellationToken.throwIfCancellationRequested(); + } + } + function getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications { synchronizeHostData(); @@ -6131,7 +6160,10 @@ namespace ts { function processNode(node: Node) { // Only walk into nodes that intersect the requested span. if (node && textSpanIntersectsWith(span, node.getFullStart(), node.getFullWidth())) { - if (node.kind === SyntaxKind.Identifier && !nodeIsMissing(node)) { + let kind = node.kind; + checkForClassificationCancellation(kind); + + if (kind === SyntaxKind.Identifier && !nodeIsMissing(node)) { let identifier = node; // Only bother calling into the typechecker if this is an identifier that @@ -6498,6 +6530,8 @@ namespace ts { // Ignore nodes that don't intersect the original span to classify. if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) { + checkForClassificationCancellation(element.kind); + let children = element.getChildren(sourceFile); for (let i = 0, n = children.length; i < n; i++) { let child = children[i]; diff --git a/src/services/shims.ts b/src/services/shims.ts index 2e8b3eb774d..6e765eff499 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -51,7 +51,7 @@ namespace ts { getScriptVersion(fileName: string): string; getScriptSnapshot(fileName: string): ScriptSnapshotShim; getLocalizedDiagnosticMessages(): string; - getCancellationToken(): CancellationToken; + getCancellationToken(): HostCancellationToken; getCurrentDirectory(): string; getDefaultLibFileName(options: string): string; getNewLine?(): string; @@ -326,8 +326,9 @@ namespace ts { } } - public getCancellationToken(): CancellationToken { - return this.shimHost.getCancellationToken(); + public getCancellationToken(): HostCancellationToken { + var hostCancellationToken = this.shimHost.getCancellationToken(); + return new ThrottledCancellationToken(hostCancellationToken); } public getCurrentDirectory(): string { @@ -346,6 +347,29 @@ namespace ts { } } + /** A cancellation that throttles calls to the host */ + class ThrottledCancellationToken implements HostCancellationToken { + // Store when we last tried to cancel. Checking cancellation can be expensive (as we have + // to marshall over to the host layer). So we only bother actually checking once enough + // time has passed. + private lastCancellationCheckTime = 0; + + constructor(private hostCancellationToken: HostCancellationToken) { + } + + public isCancellationRequested(): boolean { + var time = Date.now(); + var duration = Math.abs(time - this.lastCancellationCheckTime); + if (duration > 10) { + // Check no more than once every 10 ms. + this.lastCancellationCheckTime = time; + return this.hostCancellationToken.isCancellationRequested(); + } + + return false; + } + } + export class CoreServicesShimHostAdapter implements ParseConfigHost { constructor(private shimHost: CoreServicesShimHost) { diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index fce4e2c3025..44b022a7b12 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -178,7 +178,7 @@ namespace ts.SignatureHelp { argumentCount: number; } - export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationTokenObject): SignatureHelpItems { + export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationToken): SignatureHelpItems { let typeChecker = program.getTypeChecker(); // Decide whether to show signature help diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index b49c2d7596e..30951b90fca 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -75,26 +75,26 @@ function delint(sourceFile) { delintNode(sourceFile); function delintNode(node) { switch (node.kind) { - case 195 /* ForStatement */: - case 196 /* ForInStatement */: - case 194 /* WhileStatement */: - case 193 /* DoStatement */: - if (node.statement.kind !== 188 /* Block */) { + case 196 /* ForStatement */: + case 197 /* ForInStatement */: + case 195 /* WhileStatement */: + case 194 /* DoStatement */: + if (node.statement.kind !== 189 /* Block */) { report(node, "A looping statement's contents should be wrapped in a block body."); } break; - case 192 /* IfStatement */: + case 193 /* IfStatement */: var ifStatement = node; - if (ifStatement.thenStatement.kind !== 188 /* Block */) { + if (ifStatement.thenStatement.kind !== 189 /* Block */) { report(ifStatement.thenStatement, "An if statement's contents should be wrapped in a block body."); } if (ifStatement.elseStatement && - ifStatement.elseStatement.kind !== 188 /* Block */ && - ifStatement.elseStatement.kind !== 192 /* IfStatement */) { + ifStatement.elseStatement.kind !== 189 /* Block */ && + ifStatement.elseStatement.kind !== 193 /* IfStatement */) { report(ifStatement.elseStatement, "An else statement's contents should be wrapped in a block body."); } break; - case 177 /* BinaryExpression */: + case 178 /* BinaryExpression */: var op = node.operatorToken.kind; if (op === 29 /* EqualsEqualsToken */ || op == 30 /* ExclamationEqualsToken */) { report(node, "Use '===' and '!=='."); diff --git a/tests/baselines/reference/compoundAdditionAssignmentLHSCanBeAssigned.types b/tests/baselines/reference/compoundAdditionAssignmentLHSCanBeAssigned.types index e40422450b4..92835611c6d 100644 --- a/tests/baselines/reference/compoundAdditionAssignmentLHSCanBeAssigned.types +++ b/tests/baselines/reference/compoundAdditionAssignmentLHSCanBeAssigned.types @@ -98,7 +98,7 @@ x2 += E.a; x2 += {}; >x2 += {} : string >x2 : string ->{} : {} +>{} : { [x: number]: undefined; } x2 += null; >x2 += null : string diff --git a/tests/baselines/reference/contextualIntersectionType.js b/tests/baselines/reference/contextualIntersectionType.js new file mode 100644 index 00000000000..d61fc52fce7 --- /dev/null +++ b/tests/baselines/reference/contextualIntersectionType.js @@ -0,0 +1,14 @@ +//// [contextualIntersectionType.ts] +var x: { a: (s: string) => string } & { b: (n: number) => number }; +x = { + a: s => s, + b: n => n +}; + + +//// [contextualIntersectionType.js] +var x; +x = { + a: function (s) { return s; }, + b: function (n) { return n; } +}; diff --git a/tests/baselines/reference/contextualIntersectionType.symbols b/tests/baselines/reference/contextualIntersectionType.symbols new file mode 100644 index 00000000000..cb7ac9f3d41 --- /dev/null +++ b/tests/baselines/reference/contextualIntersectionType.symbols @@ -0,0 +1,23 @@ +=== tests/cases/conformance/types/intersection/contextualIntersectionType.ts === +var x: { a: (s: string) => string } & { b: (n: number) => number }; +>x : Symbol(x, Decl(contextualIntersectionType.ts, 0, 3)) +>a : Symbol(a, Decl(contextualIntersectionType.ts, 0, 8)) +>s : Symbol(s, Decl(contextualIntersectionType.ts, 0, 13)) +>b : Symbol(b, Decl(contextualIntersectionType.ts, 0, 39)) +>n : Symbol(n, Decl(contextualIntersectionType.ts, 0, 44)) + +x = { +>x : Symbol(x, Decl(contextualIntersectionType.ts, 0, 3)) + + a: s => s, +>a : Symbol(a, Decl(contextualIntersectionType.ts, 1, 5)) +>s : Symbol(s, Decl(contextualIntersectionType.ts, 2, 6)) +>s : Symbol(s, Decl(contextualIntersectionType.ts, 2, 6)) + + b: n => n +>b : Symbol(b, Decl(contextualIntersectionType.ts, 2, 14)) +>n : Symbol(n, Decl(contextualIntersectionType.ts, 3, 6)) +>n : Symbol(n, Decl(contextualIntersectionType.ts, 3, 6)) + +}; + diff --git a/tests/baselines/reference/contextualIntersectionType.types b/tests/baselines/reference/contextualIntersectionType.types new file mode 100644 index 00000000000..4967979d736 --- /dev/null +++ b/tests/baselines/reference/contextualIntersectionType.types @@ -0,0 +1,27 @@ +=== tests/cases/conformance/types/intersection/contextualIntersectionType.ts === +var x: { a: (s: string) => string } & { b: (n: number) => number }; +>x : { a: (s: string) => string; } & { b: (n: number) => number; } +>a : (s: string) => string +>s : string +>b : (n: number) => number +>n : number + +x = { +>x = { a: s => s, b: n => n} : { a: (s: string) => string; b: (n: number) => number; } +>x : { a: (s: string) => string; } & { b: (n: number) => number; } +>{ a: s => s, b: n => n} : { a: (s: string) => string; b: (n: number) => number; } + + a: s => s, +>a : (s: string) => string +>s => s : (s: string) => string +>s : string +>s : string + + b: n => n +>b : (n: number) => number +>n => n : (n: number) => number +>n : number +>n : number + +}; + diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols index 172336603ab..3e23a7812f5 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols +++ b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols @@ -82,5 +82,7 @@ var x4: IWithCallSignatures | IWithCallSignatures4 = a => /*here a should be any >IWithCallSignatures : Symbol(IWithCallSignatures, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 9, 1)) >IWithCallSignatures4 : Symbol(IWithCallSignatures4, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 18, 1)) >a : Symbol(a, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 35, 52)) +>a.toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18)) >a : Symbol(a, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 35, 52)) +>toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18)) diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types index 02dfecf5c08..8e1915d4754 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types +++ b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types @@ -90,10 +90,10 @@ var x4: IWithCallSignatures | IWithCallSignatures4 = a => /*here a should be any >x4 : IWithCallSignatures | IWithCallSignatures4 >IWithCallSignatures : IWithCallSignatures >IWithCallSignatures4 : IWithCallSignatures4 ->a => /*here a should be any*/ a.toString() : (a: any) => any ->a : any ->a.toString() : any ->a.toString : any ->a : any ->toString : any +>a => /*here a should be any*/ a.toString() : (a: number) => string +>a : number +>a.toString() : string +>a.toString : (radix?: number) => string +>a : number +>toString : (radix?: number) => string diff --git a/tests/baselines/reference/functionConstraintSatisfaction3.types b/tests/baselines/reference/functionConstraintSatisfaction3.types index 04963c36519..c58e62f6995 100644 --- a/tests/baselines/reference/functionConstraintSatisfaction3.types +++ b/tests/baselines/reference/functionConstraintSatisfaction3.types @@ -37,12 +37,12 @@ var c: { (): string; (x): string }; >x : any var r1 = foo((x) => x); ->r1 : (x: any) => any ->foo((x) => x) : (x: any) => any +>r1 : (x: string) => string +>foo((x) => x) : (x: string) => string >foo : string>(x: T) => T ->(x) => x : (x: any) => any ->x : any ->x : any +>(x) => x : (x: string) => string +>x : string +>x : string var r2 = foo((x: string) => x); >r2 : (x: string) => string @@ -53,12 +53,12 @@ var r2 = foo((x: string) => x); >x : string var r3 = foo(function (x) { return x }); ->r3 : (x: any) => any ->foo(function (x) { return x }) : (x: any) => any +>r3 : (x: string) => string +>foo(function (x) { return x }) : (x: string) => string >foo : string>(x: T) => T ->function (x) { return x } : (x: any) => any ->x : any ->x : any +>function (x) { return x } : (x: string) => string +>x : string +>x : string var r4 = foo(function (x: string) { return x }); >r4 : (x: string) => string @@ -130,8 +130,8 @@ var c2: { (x: T): T; (x: T, y: T): T }; >T : T var r9 = foo(function (x: U) { return x; }); ->r9 : (x: U) => U ->foo(function (x: U) { return x; }) : (x: U) => U +>r9 : (x: string) => string +>foo(function (x: U) { return x; }) : (x: string) => string >foo : string>(x: T) => T >function (x: U) { return x; } : (x: U) => U >U : U @@ -140,8 +140,8 @@ var r9 = foo(function (x: U) { return x; }); >x : U var r10 = foo((x: U) => x); ->r10 : (x: U) => U ->foo((x: U) => x) : (x: U) => U +>r10 : (x: string) => string +>foo((x: U) => x) : (x: string) => string >foo : string>(x: T) => T >(x: U) => x : (x: U) => U >U : U diff --git a/tests/baselines/reference/genericCallWithTupleType.errors.txt b/tests/baselines/reference/genericCallWithTupleType.errors.txt index bcf580320e5..d03f8d5e68a 100644 --- a/tests/baselines/reference/genericCallWithTupleType.errors.txt +++ b/tests/baselines/reference/genericCallWithTupleType.errors.txt @@ -9,9 +9,9 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(22,1): error TS2322: Type '[number, string]' is not assignable to type '[string, number]'. Types of property '0' are incompatible. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(23,1): error TS2322: Type '[{}, {}]' is not assignable to type '[string, number]'. +tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(23,1): error TS2322: Type '[{ [x: number]: undefined; }, {}]' is not assignable to type '[string, number]'. Types of property '0' are incompatible. - Type '{}' is not assignable to type 'string'. + Type '{ [x: number]: undefined; }' is not assignable to type 'string'. tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(24,1): error TS2322: Type '[{}]' is not assignable to type '[{}, {}]'. Property '1' is missing in type '[{}]'. @@ -55,9 +55,9 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup !!! error TS2322: Type 'number' is not assignable to type 'string'. i1.tuple1 = [{}, {}]; ~~~~~~~~~ -!!! error TS2322: Type '[{}, {}]' is not assignable to type '[string, number]'. +!!! error TS2322: Type '[{ [x: number]: undefined; }, {}]' is not assignable to type '[string, number]'. !!! error TS2322: Types of property '0' are incompatible. -!!! error TS2322: Type '{}' is not assignable to type 'string'. +!!! error TS2322: Type '{ [x: number]: undefined; }' is not assignable to type 'string'. i2.tuple1 = [{}]; ~~~~~~~~~ !!! error TS2322: Type '[{}]' is not assignable to type '[{}, {}]'. diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType1.js b/tests/baselines/reference/inferentialTypingUsingApparentType1.js new file mode 100644 index 00000000000..02161a98695 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType1.js @@ -0,0 +1,12 @@ +//// [inferentialTypingUsingApparentType1.ts] +function foo number>(x: T): T { + return undefined; +} + +foo(x => x.length); + +//// [inferentialTypingUsingApparentType1.js] +function foo(x) { + return undefined; +} +foo(function (x) { return x.length; }); diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType1.symbols b/tests/baselines/reference/inferentialTypingUsingApparentType1.symbols new file mode 100644 index 00000000000..4babc614183 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType1.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/inferentialTypingUsingApparentType1.ts === +function foo number>(x: T): T { +>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType1.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType1.ts, 0, 13)) +>p : Symbol(p, Decl(inferentialTypingUsingApparentType1.ts, 0, 24)) +>x : Symbol(x, Decl(inferentialTypingUsingApparentType1.ts, 0, 46)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType1.ts, 0, 13)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType1.ts, 0, 13)) + + return undefined; +>undefined : Symbol(undefined) +} + +foo(x => x.length); +>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType1.ts, 0, 0)) +>x : Symbol(x, Decl(inferentialTypingUsingApparentType1.ts, 4, 4)) +>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>x : Symbol(x, Decl(inferentialTypingUsingApparentType1.ts, 4, 4)) +>length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) + diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType1.types b/tests/baselines/reference/inferentialTypingUsingApparentType1.types new file mode 100644 index 00000000000..b56f3670ddc --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType1.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/inferentialTypingUsingApparentType1.ts === +function foo number>(x: T): T { +>foo : number>(x: T) => T +>T : T +>p : string +>x : T +>T : T +>T : T + + return undefined; +>undefined : undefined +} + +foo(x => x.length); +>foo(x => x.length) : (x: string) => number +>foo : number>(x: T) => T +>x => x.length : (x: string) => number +>x : string +>x.length : number +>x : string +>length : number + diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType2.js b/tests/baselines/reference/inferentialTypingUsingApparentType2.js new file mode 100644 index 00000000000..7cb7e49cd62 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType2.js @@ -0,0 +1,12 @@ +//// [inferentialTypingUsingApparentType2.ts] +function foo(x: T): T { + return undefined; +} + +foo({ m(x) { return x.length } }); + +//// [inferentialTypingUsingApparentType2.js] +function foo(x) { + return undefined; +} +foo({ m: function (x) { return x.length; } }); diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType2.symbols b/tests/baselines/reference/inferentialTypingUsingApparentType2.symbols new file mode 100644 index 00000000000..3c47eb4c697 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType2.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/inferentialTypingUsingApparentType2.ts === +function foo(x: T): T { +>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType2.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType2.ts, 0, 13)) +>m : Symbol(m, Decl(inferentialTypingUsingApparentType2.ts, 0, 24)) +>p : Symbol(p, Decl(inferentialTypingUsingApparentType2.ts, 0, 27)) +>x : Symbol(x, Decl(inferentialTypingUsingApparentType2.ts, 0, 49)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType2.ts, 0, 13)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType2.ts, 0, 13)) + + return undefined; +>undefined : Symbol(undefined) +} + +foo({ m(x) { return x.length } }); +>foo : Symbol(foo, Decl(inferentialTypingUsingApparentType2.ts, 0, 0)) +>m : Symbol(m, Decl(inferentialTypingUsingApparentType2.ts, 4, 5)) +>x : Symbol(x, Decl(inferentialTypingUsingApparentType2.ts, 4, 8)) +>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) +>x : Symbol(x, Decl(inferentialTypingUsingApparentType2.ts, 4, 8)) +>length : Symbol(String.length, Decl(lib.d.ts, 414, 19)) + diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType2.types b/tests/baselines/reference/inferentialTypingUsingApparentType2.types new file mode 100644 index 00000000000..597f5885f5a --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType2.types @@ -0,0 +1,24 @@ +=== tests/cases/compiler/inferentialTypingUsingApparentType2.ts === +function foo(x: T): T { +>foo : (x: T) => T +>T : T +>m : (p: string) => number +>p : string +>x : T +>T : T +>T : T + + return undefined; +>undefined : undefined +} + +foo({ m(x) { return x.length } }); +>foo({ m(x) { return x.length } }) : { } +>foo : (x: T) => T +>{ m(x) { return x.length } } : { m(x: string): number; } +>m : (x: string) => number +>x : string +>x.length : number +>x : string +>length : number + diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType3.js b/tests/baselines/reference/inferentialTypingUsingApparentType3.js new file mode 100644 index 00000000000..819ca05098d --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType3.js @@ -0,0 +1,56 @@ +//// [inferentialTypingUsingApparentType3.ts] +interface Field { + clean(input: T): T +} + +class CharField implements Field { + clean(input: string) { + return "Yup"; + } +} + +class NumberField implements Field { + clean(input: number) { + return 123; + } +} + +class ObjectField }> { + constructor(public fields: T) { } +} + +var person = new ObjectField({ + id: new NumberField(), + name: new CharField() +}); + +person.fields.id; + +//// [inferentialTypingUsingApparentType3.js] +var CharField = (function () { + function CharField() { + } + CharField.prototype.clean = function (input) { + return "Yup"; + }; + return CharField; +})(); +var NumberField = (function () { + function NumberField() { + } + NumberField.prototype.clean = function (input) { + return 123; + }; + return NumberField; +})(); +var ObjectField = (function () { + function ObjectField(fields) { + this.fields = fields; + } + return ObjectField; +})(); +var person = new ObjectField({ + id: new NumberField(), + name: new CharField() +}); +person.fields.id; diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType3.symbols b/tests/baselines/reference/inferentialTypingUsingApparentType3.symbols new file mode 100644 index 00000000000..ac3058e8649 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType3.symbols @@ -0,0 +1,69 @@ +=== tests/cases/compiler/inferentialTypingUsingApparentType3.ts === +interface Field { +>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 0, 16)) + + clean(input: T): T +>clean : Symbol(clean, Decl(inferentialTypingUsingApparentType3.ts, 0, 20)) +>input : Symbol(input, Decl(inferentialTypingUsingApparentType3.ts, 1, 10)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 0, 16)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 0, 16)) +} + +class CharField implements Field { +>CharField : Symbol(CharField, Decl(inferentialTypingUsingApparentType3.ts, 2, 1)) +>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0)) + + clean(input: string) { +>clean : Symbol(clean, Decl(inferentialTypingUsingApparentType3.ts, 4, 42)) +>input : Symbol(input, Decl(inferentialTypingUsingApparentType3.ts, 5, 10)) + + return "Yup"; + } +} + +class NumberField implements Field { +>NumberField : Symbol(NumberField, Decl(inferentialTypingUsingApparentType3.ts, 8, 1)) +>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0)) + + clean(input: number) { +>clean : Symbol(clean, Decl(inferentialTypingUsingApparentType3.ts, 10, 44)) +>input : Symbol(input, Decl(inferentialTypingUsingApparentType3.ts, 11, 10)) + + return 123; + } +} + +class ObjectField }> { +>ObjectField : Symbol(ObjectField, Decl(inferentialTypingUsingApparentType3.ts, 14, 1)) +>A : Symbol(A, Decl(inferentialTypingUsingApparentType3.ts, 16, 18)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 16, 20)) +>name : Symbol(name, Decl(inferentialTypingUsingApparentType3.ts, 16, 34)) +>Field : Symbol(Field, Decl(inferentialTypingUsingApparentType3.ts, 0, 0)) + + constructor(public fields: T) { } +>fields : Symbol(fields, Decl(inferentialTypingUsingApparentType3.ts, 17, 16)) +>T : Symbol(T, Decl(inferentialTypingUsingApparentType3.ts, 16, 20)) +} + +var person = new ObjectField({ +>person : Symbol(person, Decl(inferentialTypingUsingApparentType3.ts, 20, 3)) +>ObjectField : Symbol(ObjectField, Decl(inferentialTypingUsingApparentType3.ts, 14, 1)) + + id: new NumberField(), +>id : Symbol(id, Decl(inferentialTypingUsingApparentType3.ts, 20, 30)) +>NumberField : Symbol(NumberField, Decl(inferentialTypingUsingApparentType3.ts, 8, 1)) + + name: new CharField() +>name : Symbol(name, Decl(inferentialTypingUsingApparentType3.ts, 21, 26)) +>CharField : Symbol(CharField, Decl(inferentialTypingUsingApparentType3.ts, 2, 1)) + +}); + +person.fields.id; +>person.fields.id : Symbol(id, Decl(inferentialTypingUsingApparentType3.ts, 20, 30)) +>person.fields : Symbol(ObjectField.fields, Decl(inferentialTypingUsingApparentType3.ts, 17, 16)) +>person : Symbol(person, Decl(inferentialTypingUsingApparentType3.ts, 20, 3)) +>fields : Symbol(ObjectField.fields, Decl(inferentialTypingUsingApparentType3.ts, 17, 16)) +>id : Symbol(id, Decl(inferentialTypingUsingApparentType3.ts, 20, 30)) + diff --git a/tests/baselines/reference/inferentialTypingUsingApparentType3.types b/tests/baselines/reference/inferentialTypingUsingApparentType3.types new file mode 100644 index 00000000000..7d0da8f4b06 --- /dev/null +++ b/tests/baselines/reference/inferentialTypingUsingApparentType3.types @@ -0,0 +1,75 @@ +=== tests/cases/compiler/inferentialTypingUsingApparentType3.ts === +interface Field { +>Field : Field +>T : T + + clean(input: T): T +>clean : (input: T) => T +>input : T +>T : T +>T : T +} + +class CharField implements Field { +>CharField : CharField +>Field : Field + + clean(input: string) { +>clean : (input: string) => string +>input : string + + return "Yup"; +>"Yup" : string + } +} + +class NumberField implements Field { +>NumberField : NumberField +>Field : Field + + clean(input: number) { +>clean : (input: number) => number +>input : number + + return 123; +>123 : number + } +} + +class ObjectField }> { +>ObjectField : ObjectField +>A : A +>T : T +>name : string +>Field : Field + + constructor(public fields: T) { } +>fields : T +>T : T +} + +var person = new ObjectField({ +>person : ObjectField<{}, { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }> +>new ObjectField({ id: new NumberField(), name: new CharField()}) : ObjectField<{}, { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }> +>ObjectField : typeof ObjectField +>{ id: new NumberField(), name: new CharField()} : { [x: string]: CharField | NumberField; id: NumberField; name: CharField; } + + id: new NumberField(), +>id : NumberField +>new NumberField() : NumberField +>NumberField : typeof NumberField + + name: new CharField() +>name : CharField +>new CharField() : CharField +>CharField : typeof CharField + +}); + +person.fields.id; +>person.fields.id : NumberField +>person.fields : { [x: string]: CharField | NumberField; id: NumberField; name: CharField; } +>person : ObjectField<{}, { [x: string]: CharField | NumberField; id: NumberField; name: CharField; }> +>fields : { [x: string]: CharField | NumberField; id: NumberField; name: CharField; } +>id : NumberField + diff --git a/tests/baselines/reference/intersectionAndUnionTypes.errors.txt b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt new file mode 100644 index 00000000000..4f26cc63ba3 --- /dev/null +++ b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt @@ -0,0 +1,162 @@ +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(19,1): error TS2322: Type 'A' is not assignable to type 'A & B'. + Type 'A' is not assignable to type 'B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(20,1): error TS2322: Type 'B' is not assignable to type 'A & B'. + Type 'B' is not assignable to type 'A'. + Property 'a' is missing in type 'B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(23,1): error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'. + Type 'A' is not assignable to type '(A & B) | (C & D)'. + Type 'A' is not assignable to type 'C & D'. + Type 'A' is not assignable to type 'C'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(25,1): error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'. + Type 'C' is not assignable to type '(A & B) | (C & D)'. + Type 'C' is not assignable to type 'C & D'. + Type 'C' is not assignable to type 'D'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(26,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A & B'. + Type 'C & D' is not assignable to type 'A & B'. + Type 'C & D' is not assignable to type 'A'. + Type 'D' is not assignable to type 'A'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(27,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A | B'. + Type 'C & D' is not assignable to type 'A | B'. + Type 'C & D' is not assignable to type 'B'. + Type 'D' is not assignable to type 'B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(28,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C & D'. + Type 'A & B' is not assignable to type 'C & D'. + Type 'A & B' is not assignable to type 'C'. + Type 'B' is not assignable to type 'C'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(29,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C | D'. + Type 'A & B' is not assignable to type 'C | D'. + Type 'A & B' is not assignable to type 'D'. + Type 'B' is not assignable to type 'D'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(31,1): error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'. + Type 'A & B' is not assignable to type 'C | D'. + Type 'A & B' is not assignable to type 'D'. + Type 'B' is not assignable to type 'D'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(32,1): error TS2322: Type 'A | B' is not assignable to type '(A | B) & (C | D)'. + Type 'A' is not assignable to type '(A | B) & (C | D)'. + Type 'A' is not assignable to type 'C | D'. + Type 'A' is not assignable to type 'D'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(33,1): error TS2322: Type 'C & D' is not assignable to type '(A | B) & (C | D)'. + Type 'C & D' is not assignable to type 'A | B'. + Type 'C & D' is not assignable to type 'B'. + Type 'D' is not assignable to type 'B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(34,1): error TS2322: Type 'C | D' is not assignable to type '(A | B) & (C | D)'. + Type 'C' is not assignable to type '(A | B) & (C | D)'. + Type 'C' is not assignable to type 'A | B'. + Type 'C' is not assignable to type 'B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(35,1): error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A & B'. + Type '(A | B) & (C | D)' is not assignable to type 'A'. + Type 'C | D' is not assignable to type 'A'. + Type 'C' is not assignable to type 'A'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C & D'. + Type '(A | B) & (C | D)' is not assignable to type 'C'. + Type 'C | D' is not assignable to type 'C'. + Type 'D' is not assignable to type 'C'. + + +==== tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts (14 errors) ==== + interface A { a: string } + interface B { b: string } + interface C { c: string } + interface D { d: string } + + var a: A; + var b: B; + var c: C; + var d: D; + var anb: A & B; + var aob: A | B; + var cnd: C & D; + var cod: C | D; + var x: A & B | C & D; + var y: (A | B) & (C | D); + + a = anb; // Ok + b = anb; // Ok + anb = a; + ~~~ +!!! error TS2322: Type 'A' is not assignable to type 'A & B'. +!!! error TS2322: Type 'A' is not assignable to type 'B'. + anb = b; + ~~~ +!!! error TS2322: Type 'B' is not assignable to type 'A & B'. +!!! error TS2322: Type 'B' is not assignable to type 'A'. +!!! error TS2322: Property 'a' is missing in type 'B'. + + x = anb; // Ok + x = aob; + ~ +!!! error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'. +!!! error TS2322: Type 'A' is not assignable to type '(A & B) | (C & D)'. +!!! error TS2322: Type 'A' is not assignable to type 'C & D'. +!!! error TS2322: Type 'A' is not assignable to type 'C'. + x = cnd; // Ok + x = cod; + ~ +!!! error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'. +!!! error TS2322: Type 'C' is not assignable to type '(A & B) | (C & D)'. +!!! error TS2322: Type 'C' is not assignable to type 'C & D'. +!!! error TS2322: Type 'C' is not assignable to type 'D'. + anb = x; + ~~~ +!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A & B'. +!!! error TS2322: Type 'C & D' is not assignable to type 'A & B'. +!!! error TS2322: Type 'C & D' is not assignable to type 'A'. +!!! error TS2322: Type 'D' is not assignable to type 'A'. + aob = x; + ~~~ +!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A | B'. +!!! error TS2322: Type 'C & D' is not assignable to type 'A | B'. +!!! error TS2322: Type 'C & D' is not assignable to type 'B'. +!!! error TS2322: Type 'D' is not assignable to type 'B'. + cnd = x; + ~~~ +!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C & D'. +!!! error TS2322: Type 'A & B' is not assignable to type 'C & D'. +!!! error TS2322: Type 'A & B' is not assignable to type 'C'. +!!! error TS2322: Type 'B' is not assignable to type 'C'. + cod = x; + ~~~ +!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C | D'. +!!! error TS2322: Type 'A & B' is not assignable to type 'C | D'. +!!! error TS2322: Type 'A & B' is not assignable to type 'D'. +!!! error TS2322: Type 'B' is not assignable to type 'D'. + + y = anb; + ~ +!!! error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'. +!!! error TS2322: Type 'A & B' is not assignable to type 'C | D'. +!!! error TS2322: Type 'A & B' is not assignable to type 'D'. +!!! error TS2322: Type 'B' is not assignable to type 'D'. + y = aob; + ~ +!!! error TS2322: Type 'A | B' is not assignable to type '(A | B) & (C | D)'. +!!! error TS2322: Type 'A' is not assignable to type '(A | B) & (C | D)'. +!!! error TS2322: Type 'A' is not assignable to type 'C | D'. +!!! error TS2322: Type 'A' is not assignable to type 'D'. + y = cnd; + ~ +!!! error TS2322: Type 'C & D' is not assignable to type '(A | B) & (C | D)'. +!!! error TS2322: Type 'C & D' is not assignable to type 'A | B'. +!!! error TS2322: Type 'C & D' is not assignable to type 'B'. +!!! error TS2322: Type 'D' is not assignable to type 'B'. + y = cod; + ~ +!!! error TS2322: Type 'C | D' is not assignable to type '(A | B) & (C | D)'. +!!! error TS2322: Type 'C' is not assignable to type '(A | B) & (C | D)'. +!!! error TS2322: Type 'C' is not assignable to type 'A | B'. +!!! error TS2322: Type 'C' is not assignable to type 'B'. + anb = y; + ~~~ +!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A & B'. +!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A'. +!!! error TS2322: Type 'C | D' is not assignable to type 'A'. +!!! error TS2322: Type 'C' is not assignable to type 'A'. + aob = y; // Ok + cnd = y; + ~~~ +!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C & D'. +!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C'. +!!! error TS2322: Type 'C | D' is not assignable to type 'C'. +!!! error TS2322: Type 'D' is not assignable to type 'C'. + cod = y; // Ok + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionAndUnionTypes.js b/tests/baselines/reference/intersectionAndUnionTypes.js new file mode 100644 index 00000000000..ec0adaab8b8 --- /dev/null +++ b/tests/baselines/reference/intersectionAndUnionTypes.js @@ -0,0 +1,72 @@ +//// [intersectionAndUnionTypes.ts] +interface A { a: string } +interface B { b: string } +interface C { c: string } +interface D { d: string } + +var a: A; +var b: B; +var c: C; +var d: D; +var anb: A & B; +var aob: A | B; +var cnd: C & D; +var cod: C | D; +var x: A & B | C & D; +var y: (A | B) & (C | D); + +a = anb; // Ok +b = anb; // Ok +anb = a; +anb = b; + +x = anb; // Ok +x = aob; +x = cnd; // Ok +x = cod; +anb = x; +aob = x; +cnd = x; +cod = x; + +y = anb; +y = aob; +y = cnd; +y = cod; +anb = y; +aob = y; // Ok +cnd = y; +cod = y; // Ok + + +//// [intersectionAndUnionTypes.js] +var a; +var b; +var c; +var d; +var anb; +var aob; +var cnd; +var cod; +var x; +var y; +a = anb; // Ok +b = anb; // Ok +anb = a; +anb = b; +x = anb; // Ok +x = aob; +x = cnd; // Ok +x = cod; +anb = x; +aob = x; +cnd = x; +cod = x; +y = anb; +y = aob; +y = cnd; +y = cod; +anb = y; +aob = y; // Ok +cnd = y; +cod = y; // Ok diff --git a/tests/baselines/reference/intersectionTypeAssignment.errors.txt b/tests/baselines/reference/intersectionTypeAssignment.errors.txt new file mode 100644 index 00000000000..11ea91d8f0e --- /dev/null +++ b/tests/baselines/reference/intersectionTypeAssignment.errors.txt @@ -0,0 +1,45 @@ +tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(8,1): error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; b: string; }'. + Property 'b' is missing in type '{ a: string; }'. +tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(9,1): error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: string; }'. + Type '{ a: string; }' is not assignable to type '{ b: string; }'. + Property 'b' is missing in type '{ a: string; }'. +tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(13,1): error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; b: string; }'. + Property 'a' is missing in type '{ b: string; }'. +tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(14,1): error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; } & { b: string; }'. + Type '{ b: string; }' is not assignable to type '{ a: string; }'. + Property 'a' is missing in type '{ b: string; }'. + + +==== tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts (4 errors) ==== + var a: { a: string }; + var b: { b: string }; + var x: { a: string, b: string }; + var y: { a: string } & { b: string }; + + a = x; + a = y; + x = a; // Error + ~ +!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; b: string; }'. +!!! error TS2322: Property 'b' is missing in type '{ a: string; }'. + y = a; // Error + ~ +!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: string; }'. +!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ b: string; }'. +!!! error TS2322: Property 'b' is missing in type '{ a: string; }'. + + b = x; + b = y; + x = b; // Error + ~ +!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; b: string; }'. +!!! error TS2322: Property 'a' is missing in type '{ b: string; }'. + y = b; // Error + ~ +!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; } & { b: string; }'. +!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; }'. +!!! error TS2322: Property 'a' is missing in type '{ b: string; }'. + + x = y; + y = x; + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionTypeAssignment.js b/tests/baselines/reference/intersectionTypeAssignment.js new file mode 100644 index 00000000000..f1cddbf3b2a --- /dev/null +++ b/tests/baselines/reference/intersectionTypeAssignment.js @@ -0,0 +1,35 @@ +//// [intersectionTypeAssignment.ts] +var a: { a: string }; +var b: { b: string }; +var x: { a: string, b: string }; +var y: { a: string } & { b: string }; + +a = x; +a = y; +x = a; // Error +y = a; // Error + +b = x; +b = y; +x = b; // Error +y = b; // Error + +x = y; +y = x; + + +//// [intersectionTypeAssignment.js] +var a; +var b; +var x; +var y; +a = x; +a = y; +x = a; // Error +y = a; // Error +b = x; +b = y; +x = b; // Error +y = b; // Error +x = y; +y = x; diff --git a/tests/baselines/reference/intersectionTypeEquivalence.js b/tests/baselines/reference/intersectionTypeEquivalence.js new file mode 100644 index 00000000000..be04bfe7947 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeEquivalence.js @@ -0,0 +1,31 @@ +//// [intersectionTypeEquivalence.ts] +interface A { a: string } +interface B { b: string } +interface C { c: string } + +// A & B is equivalent to B & A. +var y: A & B; +var y : B & A; + +// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C. +var z : A & B & C; +var z : (A & B) & C; +var z : A & (B & C); +var ab : A & B; +var bc : B & C; +var z1: typeof ab & C; +var z1: A & typeof bc; + + +//// [intersectionTypeEquivalence.js] +// A & B is equivalent to B & A. +var y; +var y; +// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C. +var z; +var z; +var z; +var ab; +var bc; +var z1; +var z1; diff --git a/tests/baselines/reference/intersectionTypeEquivalence.symbols b/tests/baselines/reference/intersectionTypeEquivalence.symbols new file mode 100644 index 00000000000..2bec452c44e --- /dev/null +++ b/tests/baselines/reference/intersectionTypeEquivalence.symbols @@ -0,0 +1,63 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts === +interface A { a: string } +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>a : Symbol(a, Decl(intersectionTypeEquivalence.ts, 0, 13)) + +interface B { b: string } +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) +>b : Symbol(b, Decl(intersectionTypeEquivalence.ts, 1, 13)) + +interface C { c: string } +>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25)) +>c : Symbol(c, Decl(intersectionTypeEquivalence.ts, 2, 13)) + +// A & B is equivalent to B & A. +var y: A & B; +>y : Symbol(y, Decl(intersectionTypeEquivalence.ts, 5, 3), Decl(intersectionTypeEquivalence.ts, 6, 3)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) + +var y : B & A; +>y : Symbol(y, Decl(intersectionTypeEquivalence.ts, 5, 3), Decl(intersectionTypeEquivalence.ts, 6, 3)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) + +// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C. +var z : A & B & C; +>z : Symbol(z, Decl(intersectionTypeEquivalence.ts, 9, 3), Decl(intersectionTypeEquivalence.ts, 10, 3), Decl(intersectionTypeEquivalence.ts, 11, 3)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) +>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25)) + +var z : (A & B) & C; +>z : Symbol(z, Decl(intersectionTypeEquivalence.ts, 9, 3), Decl(intersectionTypeEquivalence.ts, 10, 3), Decl(intersectionTypeEquivalence.ts, 11, 3)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) +>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25)) + +var z : A & (B & C); +>z : Symbol(z, Decl(intersectionTypeEquivalence.ts, 9, 3), Decl(intersectionTypeEquivalence.ts, 10, 3), Decl(intersectionTypeEquivalence.ts, 11, 3)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) +>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25)) + +var ab : A & B; +>ab : Symbol(ab, Decl(intersectionTypeEquivalence.ts, 12, 3)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) + +var bc : B & C; +>bc : Symbol(bc, Decl(intersectionTypeEquivalence.ts, 13, 3)) +>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25)) +>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25)) + +var z1: typeof ab & C; +>z1 : Symbol(z1, Decl(intersectionTypeEquivalence.ts, 14, 3), Decl(intersectionTypeEquivalence.ts, 15, 3)) +>ab : Symbol(ab, Decl(intersectionTypeEquivalence.ts, 12, 3)) +>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25)) + +var z1: A & typeof bc; +>z1 : Symbol(z1, Decl(intersectionTypeEquivalence.ts, 14, 3), Decl(intersectionTypeEquivalence.ts, 15, 3)) +>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0)) +>bc : Symbol(bc, Decl(intersectionTypeEquivalence.ts, 13, 3)) + diff --git a/tests/baselines/reference/intersectionTypeEquivalence.types b/tests/baselines/reference/intersectionTypeEquivalence.types new file mode 100644 index 00000000000..25e175275d7 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeEquivalence.types @@ -0,0 +1,63 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts === +interface A { a: string } +>A : A +>a : string + +interface B { b: string } +>B : B +>b : string + +interface C { c: string } +>C : C +>c : string + +// A & B is equivalent to B & A. +var y: A & B; +>y : A & B +>A : A +>B : B + +var y : B & A; +>y : A & B +>B : B +>A : A + +// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C. +var z : A & B & C; +>z : A & B & C +>A : A +>B : B +>C : C + +var z : (A & B) & C; +>z : A & B & C +>A : A +>B : B +>C : C + +var z : A & (B & C); +>z : A & B & C +>A : A +>B : B +>C : C + +var ab : A & B; +>ab : A & B +>A : A +>B : B + +var bc : B & C; +>bc : B & C +>B : B +>C : C + +var z1: typeof ab & C; +>z1 : A & B & C +>ab : A & B +>C : C + +var z1: A & typeof bc; +>z1 : A & B & C +>A : A +>bc : B & C + diff --git a/tests/baselines/reference/intersectionTypeInference.errors.txt b/tests/baselines/reference/intersectionTypeInference.errors.txt new file mode 100644 index 00000000000..af0b1b447bc --- /dev/null +++ b/tests/baselines/reference/intersectionTypeInference.errors.txt @@ -0,0 +1,41 @@ +tests/cases/conformance/types/intersection/intersectionTypeInference.ts(5,5): error TS2322: Type 'T' is not assignable to type 'T & U'. + Type 'T' is not assignable to type 'U'. +tests/cases/conformance/types/intersection/intersectionTypeInference.ts(6,5): error TS2322: Type 'U' is not assignable to type 'T & U'. + Type 'U' is not assignable to type 'T'. + + +==== tests/cases/conformance/types/intersection/intersectionTypeInference.ts (2 errors) ==== + function extend(obj1: T, obj2: U): T & U { + var result: T & U; + obj1 = result; + obj2 = result; + result = obj1; // Error + ~~~~~~ +!!! error TS2322: Type 'T' is not assignable to type 'T & U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. + result = obj2; // Error + ~~~~~~ +!!! error TS2322: Type 'U' is not assignable to type 'T & U'. +!!! error TS2322: Type 'U' is not assignable to type 'T'. + return result; + } + + var x = extend({ a: "hello" }, { b: 42 }); + var s = x.a; + var n = x.b; + + interface A { + a: T; + } + + interface B { + b: U; + } + + function foo(obj: A & B): T | U { + return undefined; + } + + var z = foo({ a: "hello", b: 42 }); + var z: string | number; + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionTypeInference.js b/tests/baselines/reference/intersectionTypeInference.js new file mode 100644 index 00000000000..8e7f1238c07 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeInference.js @@ -0,0 +1,47 @@ +//// [intersectionTypeInference.ts] +function extend(obj1: T, obj2: U): T & U { + var result: T & U; + obj1 = result; + obj2 = result; + result = obj1; // Error + result = obj2; // Error + return result; +} + +var x = extend({ a: "hello" }, { b: 42 }); +var s = x.a; +var n = x.b; + +interface A { + a: T; +} + +interface B { + b: U; +} + +function foo(obj: A & B): T | U { + return undefined; +} + +var z = foo({ a: "hello", b: 42 }); +var z: string | number; + + +//// [intersectionTypeInference.js] +function extend(obj1, obj2) { + var result; + obj1 = result; + obj2 = result; + result = obj1; // Error + result = obj2; // Error + return result; +} +var x = extend({ a: "hello" }, { b: 42 }); +var s = x.a; +var n = x.b; +function foo(obj) { + return undefined; +} +var z = foo({ a: "hello", b: 42 }); +var z; diff --git a/tests/baselines/reference/intersectionTypeMembers.js b/tests/baselines/reference/intersectionTypeMembers.js new file mode 100644 index 00000000000..9c1cd75d601 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeMembers.js @@ -0,0 +1,44 @@ +//// [intersectionTypeMembers.ts] +// An intersection type has those members that are present in any of its constituent types, +// with types that are intersections of the respective members in the constituent types + +interface A { a: string } +interface B { b: string } +interface C { c: string } + +var abc: A & B & C; +abc.a = "hello"; +abc.b = "hello"; +abc.c = "hello"; + +interface X { x: A } +interface Y { x: B } +interface Z { x: C } + +var xyz: X & Y & Z; +xyz.x.a = "hello"; +xyz.x.b = "hello"; +xyz.x.c = "hello"; + +type F1 = (x: string) => string; +type F2 = (x: number) => number; + +var f: F1 & F2; +var s = f("hello"); +var n = f(42); + + +//// [intersectionTypeMembers.js] +// An intersection type has those members that are present in any of its constituent types, +// with types that are intersections of the respective members in the constituent types +var abc; +abc.a = "hello"; +abc.b = "hello"; +abc.c = "hello"; +var xyz; +xyz.x.a = "hello"; +xyz.x.b = "hello"; +xyz.x.c = "hello"; +var f; +var s = f("hello"); +var n = f(42); diff --git a/tests/baselines/reference/intersectionTypeMembers.symbols b/tests/baselines/reference/intersectionTypeMembers.symbols new file mode 100644 index 00000000000..ebec69b4ebe --- /dev/null +++ b/tests/baselines/reference/intersectionTypeMembers.symbols @@ -0,0 +1,100 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeMembers.ts === +// An intersection type has those members that are present in any of its constituent types, +// with types that are intersections of the respective members in the constituent types + +interface A { a: string } +>A : Symbol(A, Decl(intersectionTypeMembers.ts, 0, 0)) +>a : Symbol(a, Decl(intersectionTypeMembers.ts, 3, 13)) + +interface B { b: string } +>B : Symbol(B, Decl(intersectionTypeMembers.ts, 3, 25)) +>b : Symbol(b, Decl(intersectionTypeMembers.ts, 4, 13)) + +interface C { c: string } +>C : Symbol(C, Decl(intersectionTypeMembers.ts, 4, 25)) +>c : Symbol(c, Decl(intersectionTypeMembers.ts, 5, 13)) + +var abc: A & B & C; +>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3)) +>A : Symbol(A, Decl(intersectionTypeMembers.ts, 0, 0)) +>B : Symbol(B, Decl(intersectionTypeMembers.ts, 3, 25)) +>C : Symbol(C, Decl(intersectionTypeMembers.ts, 4, 25)) + +abc.a = "hello"; +>abc.a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13)) +>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3)) +>a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13)) + +abc.b = "hello"; +>abc.b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13)) +>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3)) +>b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13)) + +abc.c = "hello"; +>abc.c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13)) +>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3)) +>c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13)) + +interface X { x: A } +>X : Symbol(X, Decl(intersectionTypeMembers.ts, 10, 16)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13)) +>A : Symbol(A, Decl(intersectionTypeMembers.ts, 0, 0)) + +interface Y { x: B } +>Y : Symbol(Y, Decl(intersectionTypeMembers.ts, 12, 20)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 13, 13)) +>B : Symbol(B, Decl(intersectionTypeMembers.ts, 3, 25)) + +interface Z { x: C } +>Z : Symbol(Z, Decl(intersectionTypeMembers.ts, 13, 20)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 14, 13)) +>C : Symbol(C, Decl(intersectionTypeMembers.ts, 4, 25)) + +var xyz: X & Y & Z; +>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3)) +>X : Symbol(X, Decl(intersectionTypeMembers.ts, 10, 16)) +>Y : Symbol(Y, Decl(intersectionTypeMembers.ts, 12, 20)) +>Z : Symbol(Z, Decl(intersectionTypeMembers.ts, 13, 20)) + +xyz.x.a = "hello"; +>xyz.x.a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13)) +>xyz.x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13)) +>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13)) +>a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13)) + +xyz.x.b = "hello"; +>xyz.x.b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13)) +>xyz.x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13)) +>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13)) +>b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13)) + +xyz.x.c = "hello"; +>xyz.x.c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13)) +>xyz.x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13)) +>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13)) +>c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13)) + +type F1 = (x: string) => string; +>F1 : Symbol(F1, Decl(intersectionTypeMembers.ts, 19, 18)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 21, 11)) + +type F2 = (x: number) => number; +>F2 : Symbol(F2, Decl(intersectionTypeMembers.ts, 21, 32)) +>x : Symbol(x, Decl(intersectionTypeMembers.ts, 22, 11)) + +var f: F1 & F2; +>f : Symbol(f, Decl(intersectionTypeMembers.ts, 24, 3)) +>F1 : Symbol(F1, Decl(intersectionTypeMembers.ts, 19, 18)) +>F2 : Symbol(F2, Decl(intersectionTypeMembers.ts, 21, 32)) + +var s = f("hello"); +>s : Symbol(s, Decl(intersectionTypeMembers.ts, 25, 3)) +>f : Symbol(f, Decl(intersectionTypeMembers.ts, 24, 3)) + +var n = f(42); +>n : Symbol(n, Decl(intersectionTypeMembers.ts, 26, 3)) +>f : Symbol(f, Decl(intersectionTypeMembers.ts, 24, 3)) + diff --git a/tests/baselines/reference/intersectionTypeMembers.types b/tests/baselines/reference/intersectionTypeMembers.types new file mode 100644 index 00000000000..a97a54c7a81 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeMembers.types @@ -0,0 +1,116 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeMembers.ts === +// An intersection type has those members that are present in any of its constituent types, +// with types that are intersections of the respective members in the constituent types + +interface A { a: string } +>A : A +>a : string + +interface B { b: string } +>B : B +>b : string + +interface C { c: string } +>C : C +>c : string + +var abc: A & B & C; +>abc : A & B & C +>A : A +>B : B +>C : C + +abc.a = "hello"; +>abc.a = "hello" : string +>abc.a : string +>abc : A & B & C +>a : string +>"hello" : string + +abc.b = "hello"; +>abc.b = "hello" : string +>abc.b : string +>abc : A & B & C +>b : string +>"hello" : string + +abc.c = "hello"; +>abc.c = "hello" : string +>abc.c : string +>abc : A & B & C +>c : string +>"hello" : string + +interface X { x: A } +>X : X +>x : A +>A : A + +interface Y { x: B } +>Y : Y +>x : B +>B : B + +interface Z { x: C } +>Z : Z +>x : C +>C : C + +var xyz: X & Y & Z; +>xyz : X & Y & Z +>X : X +>Y : Y +>Z : Z + +xyz.x.a = "hello"; +>xyz.x.a = "hello" : string +>xyz.x.a : string +>xyz.x : A & B & C +>xyz : X & Y & Z +>x : A & B & C +>a : string +>"hello" : string + +xyz.x.b = "hello"; +>xyz.x.b = "hello" : string +>xyz.x.b : string +>xyz.x : A & B & C +>xyz : X & Y & Z +>x : A & B & C +>b : string +>"hello" : string + +xyz.x.c = "hello"; +>xyz.x.c = "hello" : string +>xyz.x.c : string +>xyz.x : A & B & C +>xyz : X & Y & Z +>x : A & B & C +>c : string +>"hello" : string + +type F1 = (x: string) => string; +>F1 : (x: string) => string +>x : string + +type F2 = (x: number) => number; +>F2 : (x: number) => number +>x : number + +var f: F1 & F2; +>f : ((x: string) => string) & ((x: number) => number) +>F1 : (x: string) => string +>F2 : (x: number) => number + +var s = f("hello"); +>s : string +>f("hello") : string +>f : ((x: string) => string) & ((x: number) => number) +>"hello" : string + +var n = f(42); +>n : number +>f(42) : number +>f : ((x: string) => string) & ((x: number) => number) +>42 : number + diff --git a/tests/baselines/reference/intersectionTypeOverloading.js b/tests/baselines/reference/intersectionTypeOverloading.js new file mode 100644 index 00000000000..b7080e449b7 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeOverloading.js @@ -0,0 +1,26 @@ +//// [intersectionTypeOverloading.ts] +// Check that order is preserved in intersection types for purposes of +// overload resolution + +type F = (s: string) => string; +type G = (x: any) => any; + +var fg: F & G; +var gf: G & F; + +var x = fg("abc"); +var x: string; + +var y = gf("abc"); +var y: any; + + +//// [intersectionTypeOverloading.js] +// Check that order is preserved in intersection types for purposes of +// overload resolution +var fg; +var gf; +var x = fg("abc"); +var x; +var y = gf("abc"); +var y; diff --git a/tests/baselines/reference/intersectionTypeOverloading.symbols b/tests/baselines/reference/intersectionTypeOverloading.symbols new file mode 100644 index 00000000000..c8503345041 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeOverloading.symbols @@ -0,0 +1,36 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts === +// Check that order is preserved in intersection types for purposes of +// overload resolution + +type F = (s: string) => string; +>F : Symbol(F, Decl(intersectionTypeOverloading.ts, 0, 0)) +>s : Symbol(s, Decl(intersectionTypeOverloading.ts, 3, 10)) + +type G = (x: any) => any; +>G : Symbol(G, Decl(intersectionTypeOverloading.ts, 3, 31)) +>x : Symbol(x, Decl(intersectionTypeOverloading.ts, 4, 10)) + +var fg: F & G; +>fg : Symbol(fg, Decl(intersectionTypeOverloading.ts, 6, 3)) +>F : Symbol(F, Decl(intersectionTypeOverloading.ts, 0, 0)) +>G : Symbol(G, Decl(intersectionTypeOverloading.ts, 3, 31)) + +var gf: G & F; +>gf : Symbol(gf, Decl(intersectionTypeOverloading.ts, 7, 3)) +>G : Symbol(G, Decl(intersectionTypeOverloading.ts, 3, 31)) +>F : Symbol(F, Decl(intersectionTypeOverloading.ts, 0, 0)) + +var x = fg("abc"); +>x : Symbol(x, Decl(intersectionTypeOverloading.ts, 9, 3), Decl(intersectionTypeOverloading.ts, 10, 3)) +>fg : Symbol(fg, Decl(intersectionTypeOverloading.ts, 6, 3)) + +var x: string; +>x : Symbol(x, Decl(intersectionTypeOverloading.ts, 9, 3), Decl(intersectionTypeOverloading.ts, 10, 3)) + +var y = gf("abc"); +>y : Symbol(y, Decl(intersectionTypeOverloading.ts, 12, 3), Decl(intersectionTypeOverloading.ts, 13, 3)) +>gf : Symbol(gf, Decl(intersectionTypeOverloading.ts, 7, 3)) + +var y: any; +>y : Symbol(y, Decl(intersectionTypeOverloading.ts, 12, 3), Decl(intersectionTypeOverloading.ts, 13, 3)) + diff --git a/tests/baselines/reference/intersectionTypeOverloading.types b/tests/baselines/reference/intersectionTypeOverloading.types new file mode 100644 index 00000000000..c478b6a08cb --- /dev/null +++ b/tests/baselines/reference/intersectionTypeOverloading.types @@ -0,0 +1,40 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts === +// Check that order is preserved in intersection types for purposes of +// overload resolution + +type F = (s: string) => string; +>F : (s: string) => string +>s : string + +type G = (x: any) => any; +>G : (x: any) => any +>x : any + +var fg: F & G; +>fg : ((s: string) => string) & ((x: any) => any) +>F : (s: string) => string +>G : (x: any) => any + +var gf: G & F; +>gf : ((x: any) => any) & ((s: string) => string) +>G : (x: any) => any +>F : (s: string) => string + +var x = fg("abc"); +>x : string +>fg("abc") : string +>fg : ((s: string) => string) & ((x: any) => any) +>"abc" : string + +var x: string; +>x : string + +var y = gf("abc"); +>y : any +>gf("abc") : any +>gf : ((x: any) => any) & ((s: string) => string) +>"abc" : string + +var y: any; +>y : any + diff --git a/tests/baselines/reference/noErrorsInCallback.errors.txt b/tests/baselines/reference/noErrorsInCallback.errors.txt index f0bfe00199e..90fdbbd77a5 100644 --- a/tests/baselines/reference/noErrorsInCallback.errors.txt +++ b/tests/baselines/reference/noErrorsInCallback.errors.txt @@ -1,5 +1,5 @@ -tests/cases/compiler/noErrorsInCallback.ts(4,19): error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'. -tests/cases/compiler/noErrorsInCallback.ts(6,23): error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'. +tests/cases/compiler/noErrorsInCallback.ts(4,19): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'. +tests/cases/compiler/noErrorsInCallback.ts(6,23): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'. ==== tests/cases/compiler/noErrorsInCallback.ts (2 errors) ==== @@ -8,10 +8,10 @@ tests/cases/compiler/noErrorsInCallback.ts(6,23): error TS2345: Argument of type } var one = new Bar({}); // Error ~~ -!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'. +!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'. [].forEach(() => { var two = new Bar({}); // No error? ~~ -!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'string'. +!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'string'. }); \ No newline at end of file diff --git a/tests/baselines/reference/recursiveIntersectionTypes.errors.txt b/tests/baselines/reference/recursiveIntersectionTypes.errors.txt new file mode 100644 index 00000000000..bac97470e55 --- /dev/null +++ b/tests/baselines/reference/recursiveIntersectionTypes.errors.txt @@ -0,0 +1,32 @@ +tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts(19,1): error TS2322: Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product & { next: Product & any; }'. + Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product'. + Type '{ next: Entity & any; }' is not assignable to type 'Product'. + Property 'price' is missing in type '{ next: Entity & any; }'. + + +==== tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts (1 errors) ==== + type LinkedList = T & { next: LinkedList }; + + interface Entity { + name: string; + } + + interface Product extends Entity { + price: number; + } + + var entityList: LinkedList; + var s = entityList.name; + var s = entityList.next.name; + var s = entityList.next.next.name; + var s = entityList.next.next.next.name; + + var productList: LinkedList; + entityList = productList; + productList = entityList; // Error + ~~~~~~~~~~~ +!!! error TS2322: Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product & { next: Product & any; }'. +!!! error TS2322: Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product'. +!!! error TS2322: Type '{ next: Entity & any; }' is not assignable to type 'Product'. +!!! error TS2322: Property 'price' is missing in type '{ next: Entity & any; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/recursiveIntersectionTypes.js b/tests/baselines/reference/recursiveIntersectionTypes.js new file mode 100644 index 00000000000..88b7e6f831b --- /dev/null +++ b/tests/baselines/reference/recursiveIntersectionTypes.js @@ -0,0 +1,31 @@ +//// [recursiveIntersectionTypes.ts] +type LinkedList = T & { next: LinkedList }; + +interface Entity { + name: string; +} + +interface Product extends Entity { + price: number; +} + +var entityList: LinkedList; +var s = entityList.name; +var s = entityList.next.name; +var s = entityList.next.next.name; +var s = entityList.next.next.next.name; + +var productList: LinkedList; +entityList = productList; +productList = entityList; // Error + + +//// [recursiveIntersectionTypes.js] +var entityList; +var s = entityList.name; +var s = entityList.next.name; +var s = entityList.next.next.name; +var s = entityList.next.next.next.name; +var productList; +entityList = productList; +productList = entityList; // Error diff --git a/tests/baselines/reference/restParamModifier.errors.txt b/tests/baselines/reference/restParamModifier.errors.txt new file mode 100644 index 00000000000..87c73fcdc71 --- /dev/null +++ b/tests/baselines/reference/restParamModifier.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/restParamModifier.ts(2,17): error TS2370: A rest parameter must be of an array type. +tests/cases/compiler/restParamModifier.ts(2,27): error TS1005: '=' expected. +tests/cases/compiler/restParamModifier.ts(2,27): error TS2304: Cannot find name 'rest'. +tests/cases/compiler/restParamModifier.ts(2,31): error TS1005: ',' expected. +tests/cases/compiler/restParamModifier.ts(2,39): error TS1005: '=' expected. + + +==== tests/cases/compiler/restParamModifier.ts (5 errors) ==== + class C { + constructor(...public rest: string[]) {} + ~~~~~~~~~~~~~~ +!!! error TS2370: A rest parameter must be of an array type. + ~~~~ +!!! error TS1005: '=' expected. + ~~~~ +!!! error TS2304: Cannot find name 'rest'. + ~ +!!! error TS1005: ',' expected. + ~ +!!! error TS1005: '=' expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/restParamModifier.js b/tests/baselines/reference/restParamModifier.js new file mode 100644 index 00000000000..9a780321dc9 --- /dev/null +++ b/tests/baselines/reference/restParamModifier.js @@ -0,0 +1,12 @@ +//// [restParamModifier.ts] +class C { + constructor(...public rest: string[]) {} +} + +//// [restParamModifier.js] +var C = (function () { + function C(public, string) { + if (string === void 0) { string = []; } + } + return C; +})(); diff --git a/tests/baselines/reference/restParamModifier2.errors.txt b/tests/baselines/reference/restParamModifier2.errors.txt new file mode 100644 index 00000000000..773592fa9bf --- /dev/null +++ b/tests/baselines/reference/restParamModifier2.errors.txt @@ -0,0 +1,9 @@ +tests/cases/compiler/restParamModifier2.ts(2,24): error TS1005: ',' expected. + + +==== tests/cases/compiler/restParamModifier2.ts (1 errors) ==== + class C { + constructor(public ...rest: string[]) {} + ~~~ +!!! error TS1005: ',' expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/restParamModifier2.js b/tests/baselines/reference/restParamModifier2.js new file mode 100644 index 00000000000..c588c945ce4 --- /dev/null +++ b/tests/baselines/reference/restParamModifier2.js @@ -0,0 +1,15 @@ +//// [restParamModifier2.ts] +class C { + constructor(public ...rest: string[]) {} +} + +//// [restParamModifier2.js] +var C = (function () { + function C(public) { + var rest = []; + for (var _i = 1; _i < arguments.length; _i++) { + rest[_i - 1] = arguments[_i]; + } + } + return C; +})(); diff --git a/tests/baselines/reference/tsxAttributeResolution1.errors.txt b/tests/baselines/reference/tsxAttributeResolution1.errors.txt index 54666f46aba..7503c5f5969 100644 --- a/tests/baselines/reference/tsxAttributeResolution1.errors.txt +++ b/tests/baselines/reference/tsxAttributeResolution1.errors.txt @@ -1,17 +1,19 @@ -tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(22,8): error TS2322: Type 'string' is not assignable to type 'number'. -tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(23,8): error TS2339: Property 'y' does not exist on type 'Attribs1'. +tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(23,8): error TS2322: Type 'string' is not assignable to type 'number'. tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(24,8): error TS2339: Property 'y' does not exist on type 'Attribs1'. -tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(25,8): error TS2322: Type 'string' is not assignable to type 'number'. +tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(25,8): error TS2339: Property 'y' does not exist on type 'Attribs1'. +tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(26,8): error TS2322: Type 'string' is not assignable to type 'number'. +tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(27,8): error TS2339: Property 'var' does not exist on type 'Attribs1'. tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(29,1): error TS2324: Property 'reqd' is missing in type '{ reqd: string; }'. tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(30,8): error TS2322: Type 'number' is not assignable to type 'string'. -==== tests/cases/conformance/jsx/tsxAttributeResolution1.tsx (6 errors) ==== +==== tests/cases/conformance/jsx/tsxAttributeResolution1.tsx (7 errors) ==== declare module JSX { interface Element { } interface IntrinsicElements { test1: Attribs1; test2: { reqd: string }; + var: { var: string }; } } interface Attribs1 { @@ -40,8 +42,9 @@ tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(30,8): error TS2322: Typ ; // Error, "32" is not number ~~~~~~ !!! error TS2322: Type 'string' is not assignable to type 'number'. - // TODO attribute 'var' should be parseable - // ; // Error, no 'var' property + ; // Error, no 'var' property + ~~~ +!!! error TS2339: Property 'var' does not exist on type 'Attribs1'. ; // Error, missing reqd ~~~~~~~~~ @@ -50,4 +53,6 @@ tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(30,8): error TS2322: Typ ~~~~~~~~~ !!! error TS2322: Type 'number' is not assignable to type 'string'. + // Should be OK + ; \ No newline at end of file diff --git a/tests/baselines/reference/tsxAttributeResolution1.js b/tests/baselines/reference/tsxAttributeResolution1.js index 011ac8034e2..1e1efb7ea22 100644 --- a/tests/baselines/reference/tsxAttributeResolution1.js +++ b/tests/baselines/reference/tsxAttributeResolution1.js @@ -4,6 +4,7 @@ declare module JSX { interface IntrinsicElements { test1: Attribs1; test2: { reqd: string }; + var: { var: string }; } } interface Attribs1 { @@ -24,12 +25,13 @@ interface Attribs1 { ; // Error, no property "y" ; // Error, no property "y" ; // Error, "32" is not number -// TODO attribute 'var' should be parseable -// ; // Error, no 'var' property +; // Error, no 'var' property ; // Error, missing reqd ; // Error, reqd is not string +// Should be OK +; //// [tsxAttributeResolution1.jsx] @@ -44,7 +46,8 @@ interface Attribs1 { ; // Error, no property "y" ; // Error, no property "y" ; // Error, "32" is not number -// TODO attribute 'var' should be parseable -// ; // Error, no 'var' property +; // Error, no 'var' property ; // Error, missing reqd ; // Error, reqd is not string +// Should be OK +; diff --git a/tests/baselines/reference/typeParameterExtendingUnion1.symbols b/tests/baselines/reference/typeParameterExtendingUnion1.symbols index 39b67e6428c..97d900b5d5e 100644 --- a/tests/baselines/reference/typeParameterExtendingUnion1.symbols +++ b/tests/baselines/reference/typeParameterExtendingUnion1.symbols @@ -33,9 +33,9 @@ function f(a: T) { >T : Symbol(T, Decl(typeParameterExtendingUnion1.ts, 8, 11)) a.run(); ->a.run : Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14), Decl(typeParameterExtendingUnion1.ts, 0, 14)) +>a.run : Symbol(Animal.run, Decl(typeParameterExtendingUnion1.ts, 0, 14)) >a : Symbol(a, Decl(typeParameterExtendingUnion1.ts, 8, 32)) ->run : Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14), Decl(typeParameterExtendingUnion1.ts, 0, 14)) +>run : Symbol(Animal.run, Decl(typeParameterExtendingUnion1.ts, 0, 14)) run(a); >run : Symbol(run, Decl(typeParameterExtendingUnion1.ts, 2, 33)) diff --git a/tests/baselines/reference/typeParameterExtendingUnion2.symbols b/tests/baselines/reference/typeParameterExtendingUnion2.symbols index 44d47692a82..21866b3df92 100644 --- a/tests/baselines/reference/typeParameterExtendingUnion2.symbols +++ b/tests/baselines/reference/typeParameterExtendingUnion2.symbols @@ -20,9 +20,9 @@ function run(a: Cat | Dog) { >Dog : Symbol(Dog, Decl(typeParameterExtendingUnion2.ts, 1, 33)) a.run(); ->a.run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +>a.run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14)) >a : Symbol(a, Decl(typeParameterExtendingUnion2.ts, 4, 13)) ->run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +>run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14)) } function f(a: T) { @@ -34,9 +34,9 @@ function f(a: T) { >T : Symbol(T, Decl(typeParameterExtendingUnion2.ts, 8, 11)) a.run(); ->a.run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +>a.run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14)) >a : Symbol(a, Decl(typeParameterExtendingUnion2.ts, 8, 32)) ->run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +>run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14)) run(a); >run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 2, 33)) diff --git a/tests/baselines/reference/typeParameterFixingWithConstraints.types b/tests/baselines/reference/typeParameterFixingWithConstraints.types index 64876952852..22d294f9d2e 100644 --- a/tests/baselines/reference/typeParameterFixingWithConstraints.types +++ b/tests/baselines/reference/typeParameterFixingWithConstraints.types @@ -31,17 +31,17 @@ var foo: IFoo; >IFoo : IFoo foo.foo({ bar: null }, bar => null, bar => null); ->foo.foo({ bar: null }, bar => null, bar => null) : IBar +>foo.foo({ bar: null }, bar => null, bar => null) : { [x: string]: any; bar: any; } >foo.foo : (bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar >foo : IFoo >foo : (bar: TBar, bar1: (bar: TBar) => TBar, bar2: (bar: TBar) => TBar) => TBar >{ bar: null } : { [x: string]: null; bar: null; } >bar : null >null : null ->bar => null : (bar: IBar) => any ->bar : IBar +>bar => null : (bar: { [x: string]: any; bar: any; }) => any +>bar : { [x: string]: any; bar: any; } >null : null ->bar => null : (bar: IBar) => any ->bar : IBar +>bar => null : (bar: { [x: string]: any; bar: any; }) => any +>bar : { [x: string]: any; bar: any; } >null : null diff --git a/tests/baselines/reference/wrappedAndRecursiveConstraints4.errors.txt b/tests/baselines/reference/wrappedAndRecursiveConstraints4.errors.txt index 47e8e6ff4f2..60602351b46 100644 --- a/tests/baselines/reference/wrappedAndRecursiveConstraints4.errors.txt +++ b/tests/baselines/reference/wrappedAndRecursiveConstraints4.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints4.ts(13,12): error TS2345: Argument of type '{ length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'. +tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints4.ts(13,12): error TS2345: Argument of type '{ [x: number]: undefined; length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'. ==== tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints4.ts (1 errors) ==== @@ -16,4 +16,4 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursi var r = c.foo(''); var r2 = r({ length: 3, charAt: (x: number) => { '' } }); // error ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'. \ No newline at end of file +!!! error TS2345: Argument of type '{ [x: number]: undefined; length: number; charAt: (x: number) => void; }' is not assignable to parameter of type 'string'. \ No newline at end of file diff --git a/tests/cases/compiler/inferentialTypingUsingApparentType1.ts b/tests/cases/compiler/inferentialTypingUsingApparentType1.ts new file mode 100644 index 00000000000..98920cf693f --- /dev/null +++ b/tests/cases/compiler/inferentialTypingUsingApparentType1.ts @@ -0,0 +1,5 @@ +function foo number>(x: T): T { + return undefined; +} + +foo(x => x.length); \ No newline at end of file diff --git a/tests/cases/compiler/inferentialTypingUsingApparentType2.ts b/tests/cases/compiler/inferentialTypingUsingApparentType2.ts new file mode 100644 index 00000000000..8290b14927d --- /dev/null +++ b/tests/cases/compiler/inferentialTypingUsingApparentType2.ts @@ -0,0 +1,5 @@ +function foo(x: T): T { + return undefined; +} + +foo({ m(x) { return x.length } }); \ No newline at end of file diff --git a/tests/cases/compiler/inferentialTypingUsingApparentType3.ts b/tests/cases/compiler/inferentialTypingUsingApparentType3.ts new file mode 100644 index 00000000000..d1734b0d100 --- /dev/null +++ b/tests/cases/compiler/inferentialTypingUsingApparentType3.ts @@ -0,0 +1,26 @@ +interface Field { + clean(input: T): T +} + +class CharField implements Field { + clean(input: string) { + return "Yup"; + } +} + +class NumberField implements Field { + clean(input: number) { + return 123; + } +} + +class ObjectField }> { + constructor(public fields: T) { } +} + +var person = new ObjectField({ + id: new NumberField(), + name: new CharField() +}); + +person.fields.id; \ No newline at end of file diff --git a/tests/cases/compiler/restParamModifier.ts b/tests/cases/compiler/restParamModifier.ts new file mode 100644 index 00000000000..220b7d36d5e --- /dev/null +++ b/tests/cases/compiler/restParamModifier.ts @@ -0,0 +1,3 @@ +class C { + constructor(...public rest: string[]) {} +} \ No newline at end of file diff --git a/tests/cases/compiler/restParamModifier2.ts b/tests/cases/compiler/restParamModifier2.ts new file mode 100644 index 00000000000..e007bc56d7c --- /dev/null +++ b/tests/cases/compiler/restParamModifier2.ts @@ -0,0 +1,3 @@ +class C { + constructor(public ...rest: string[]) {} +} \ No newline at end of file diff --git a/tests/cases/conformance/jsx/tsxAttributeResolution1.tsx b/tests/cases/conformance/jsx/tsxAttributeResolution1.tsx index edb203655ef..eff3f3a8f43 100644 --- a/tests/cases/conformance/jsx/tsxAttributeResolution1.tsx +++ b/tests/cases/conformance/jsx/tsxAttributeResolution1.tsx @@ -5,6 +5,7 @@ declare module JSX { interface IntrinsicElements { test1: Attribs1; test2: { reqd: string }; + var: { var: string }; } } interface Attribs1 { @@ -25,9 +26,10 @@ interface Attribs1 { ; // Error, no property "y" ; // Error, no property "y" ; // Error, "32" is not number -// TODO attribute 'var' should be parseable -// ; // Error, no 'var' property +; // Error, no 'var' property ; // Error, missing reqd ; // Error, reqd is not string +// Should be OK +; diff --git a/tests/cases/conformance/types/intersection/contextualIntersectionType.ts b/tests/cases/conformance/types/intersection/contextualIntersectionType.ts new file mode 100644 index 00000000000..580827992ac --- /dev/null +++ b/tests/cases/conformance/types/intersection/contextualIntersectionType.ts @@ -0,0 +1,5 @@ +var x: { a: (s: string) => string } & { b: (n: number) => number }; +x = { + a: s => s, + b: n => n +}; diff --git a/tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts b/tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts new file mode 100644 index 00000000000..e6bd671c6b2 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts @@ -0,0 +1,38 @@ +interface A { a: string } +interface B { b: string } +interface C { c: string } +interface D { d: string } + +var a: A; +var b: B; +var c: C; +var d: D; +var anb: A & B; +var aob: A | B; +var cnd: C & D; +var cod: C | D; +var x: A & B | C & D; +var y: (A | B) & (C | D); + +a = anb; // Ok +b = anb; // Ok +anb = a; +anb = b; + +x = anb; // Ok +x = aob; +x = cnd; // Ok +x = cod; +anb = x; +aob = x; +cnd = x; +cod = x; + +y = anb; +y = aob; +y = cnd; +y = cod; +anb = y; +aob = y; // Ok +cnd = y; +cod = y; // Ok diff --git a/tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts b/tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts new file mode 100644 index 00000000000..00a299ea244 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts @@ -0,0 +1,17 @@ +var a: { a: string }; +var b: { b: string }; +var x: { a: string, b: string }; +var y: { a: string } & { b: string }; + +a = x; +a = y; +x = a; // Error +y = a; // Error + +b = x; +b = y; +x = b; // Error +y = b; // Error + +x = y; +y = x; diff --git a/tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts b/tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts new file mode 100644 index 00000000000..fce399eff94 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts @@ -0,0 +1,16 @@ +interface A { a: string } +interface B { b: string } +interface C { c: string } + +// A & B is equivalent to B & A. +var y: A & B; +var y : B & A; + +// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C. +var z : A & B & C; +var z : (A & B) & C; +var z : A & (B & C); +var ab : A & B; +var bc : B & C; +var z1: typeof ab & C; +var z1: A & typeof bc; diff --git a/tests/cases/conformance/types/intersection/intersectionTypeInference.ts b/tests/cases/conformance/types/intersection/intersectionTypeInference.ts new file mode 100644 index 00000000000..32a419ff03a --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionTypeInference.ts @@ -0,0 +1,27 @@ +function extend(obj1: T, obj2: U): T & U { + var result: T & U; + obj1 = result; + obj2 = result; + result = obj1; // Error + result = obj2; // Error + return result; +} + +var x = extend({ a: "hello" }, { b: 42 }); +var s = x.a; +var n = x.b; + +interface A { + a: T; +} + +interface B { + b: U; +} + +function foo(obj: A & B): T | U { + return undefined; +} + +var z = foo({ a: "hello", b: 42 }); +var z: string | number; diff --git a/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts b/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts new file mode 100644 index 00000000000..a8c92647f47 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionTypeMembers.ts @@ -0,0 +1,27 @@ +// An intersection type has those members that are present in any of its constituent types, +// with types that are intersections of the respective members in the constituent types + +interface A { a: string } +interface B { b: string } +interface C { c: string } + +var abc: A & B & C; +abc.a = "hello"; +abc.b = "hello"; +abc.c = "hello"; + +interface X { x: A } +interface Y { x: B } +interface Z { x: C } + +var xyz: X & Y & Z; +xyz.x.a = "hello"; +xyz.x.b = "hello"; +xyz.x.c = "hello"; + +type F1 = (x: string) => string; +type F2 = (x: number) => number; + +var f: F1 & F2; +var s = f("hello"); +var n = f(42); diff --git a/tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts b/tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts new file mode 100644 index 00000000000..0a0d30d8dbb --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts @@ -0,0 +1,14 @@ +// Check that order is preserved in intersection types for purposes of +// overload resolution + +type F = (s: string) => string; +type G = (x: any) => any; + +var fg: F & G; +var gf: G & F; + +var x = fg("abc"); +var x: string; + +var y = gf("abc"); +var y: any; diff --git a/tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts b/tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts new file mode 100644 index 00000000000..d741d30ac1f --- /dev/null +++ b/tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts @@ -0,0 +1,19 @@ +type LinkedList = T & { next: LinkedList }; + +interface Entity { + name: string; +} + +interface Product extends Entity { + price: number; +} + +var entityList: LinkedList; +var s = entityList.name; +var s = entityList.next.name; +var s = entityList.next.next.name; +var s = entityList.next.next.next.name; + +var productList: LinkedList; +entityList = productList; +productList = entityList; // Error diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern01.ts b/tests/cases/fourslash/completionListInObjectBindingPattern01.ts index 128e95b8ed3..99188457e6f 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern01.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern01.ts @@ -10,4 +10,5 @@ goTo.marker(); verify.completionListContains("property1"); -verify.completionListContains("property2"); \ No newline at end of file +verify.completionListContains("property2"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern02.ts b/tests/cases/fourslash/completionListInObjectBindingPattern02.ts index 6d2b7a6b516..0cd86c8d1a6 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern02.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern02.ts @@ -10,4 +10,5 @@ goTo.marker(); verify.completionListContains("property2"); -verify.not.completionListContains("property1"); \ No newline at end of file +verify.not.completionListContains("property1"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern04.ts b/tests/cases/fourslash/completionListInObjectBindingPattern04.ts index 92b202a1b37..e6057ec0fae 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern04.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern04.ts @@ -10,4 +10,5 @@ goTo.marker(); verify.completionListContains("property1"); -verify.completionListContains("property2"); \ No newline at end of file +verify.completionListContains("property2"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern05.ts b/tests/cases/fourslash/completionListInObjectBindingPattern05.ts index d17e11810df..d0876ed6a34 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern05.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern05.ts @@ -9,4 +9,5 @@ ////var { property1/**/ } = foo; goTo.marker(); -verify.completionListContains("property1"); \ No newline at end of file +verify.completionListContains("property1"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern07.ts b/tests/cases/fourslash/completionListInObjectBindingPattern07.ts index a3015346aa3..4db3fc383d4 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern07.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern07.ts @@ -15,4 +15,5 @@ goTo.marker(); verify.completionListContains("propertyOfI_1"); verify.completionListContains("propertyOfI_2"); -verify.not.completionListContains("property2"); \ No newline at end of file +verify.not.completionListContains("property2"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern08.ts b/tests/cases/fourslash/completionListInObjectBindingPattern08.ts index 6d6be330b83..b062ca702a2 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern08.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern08.ts @@ -15,4 +15,5 @@ goTo.marker(); verify.completionListContains("propertyOfI_2"); verify.not.completionListContains("propertyOfI_1"); -verify.not.completionListContains("property2"); \ No newline at end of file +verify.not.completionListContains("property2"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern09.ts b/tests/cases/fourslash/completionListInObjectBindingPattern09.ts index 2698e78667b..61b31385b35 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern09.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern09.ts @@ -16,4 +16,5 @@ goTo.marker(); verify.completionListContains("property2"); verify.not.completionListContains("property1"); verify.not.completionListContains("propertyOfI_2"); -verify.not.completionListContains("propertyOfI_1"); \ No newline at end of file +verify.not.completionListContains("propertyOfI_1"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern10.ts b/tests/cases/fourslash/completionListInObjectBindingPattern10.ts index fcc09d1ead4..836e12fd8a3 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern10.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern10.ts @@ -17,7 +17,9 @@ verify.completionListContains("property2"); verify.not.completionListContains("property1"); verify.not.completionListContains("propertyOfI_2"); verify.not.completionListContains("propertyOfI_1"); +verify.not.completionListAllowsNewIdentifier(); goTo.marker("2"); verify.completionListContains("property1"); -verify.completionListContains("property2"); \ No newline at end of file +verify.completionListContains("property2"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern11.ts b/tests/cases/fourslash/completionListInObjectBindingPattern11.ts index 25d6651a038..57a32578026 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern11.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern11.ts @@ -10,4 +10,5 @@ goTo.marker(""); verify.completionListContains("property2"); verify.not.completionListContains("property1"); -verify.not.completionListContains("prop1"); \ No newline at end of file +verify.not.completionListContains("prop1"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern12.ts b/tests/cases/fourslash/completionListInObjectBindingPattern12.ts index f31206a21b6..59af2da38d2 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern12.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern12.ts @@ -10,4 +10,5 @@ goTo.marker(""); verify.completionListContains("property2"); -verify.not.completionListContains("property1"); \ No newline at end of file +verify.not.completionListContains("property1"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInObjectBindingPattern13.ts b/tests/cases/fourslash/completionListInObjectBindingPattern13.ts index f91f9fcceed..8081d2ee23b 100644 --- a/tests/cases/fourslash/completionListInObjectBindingPattern13.ts +++ b/tests/cases/fourslash/completionListInObjectBindingPattern13.ts @@ -16,4 +16,5 @@ goTo.marker(); verify.completionListContains("x"); verify.completionListContains("y"); -verify.not.completionListContains("z"); \ No newline at end of file +verify.not.completionListContains("z"); +verify.not.completionListAllowsNewIdentifier(); \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificationsCancellation1.ts b/tests/cases/fourslash/semanticClassificationsCancellation1.ts new file mode 100644 index 00000000000..9381bef5e86 --- /dev/null +++ b/tests/cases/fourslash/semanticClassificationsCancellation1.ts @@ -0,0 +1,15 @@ +/// + +////module M { +////} +////module N { +////} + +var c = classification; +cancellation.setCancelled(1); +verifyOperationIsCancelled(() => verify.semanticClassificationsAre()); +cancellation.resetCancelled(); + +verify.semanticClassificationsAre( + c.moduleName("M"), + c.moduleName("N")); diff --git a/tests/cases/fourslash/shims/cancellationWhenfindingAllRefsOnDefinition.ts b/tests/cases/fourslash/shims/cancellationWhenfindingAllRefsOnDefinition.ts deleted file mode 100644 index 09f580bb965..00000000000 --- a/tests/cases/fourslash/shims/cancellationWhenfindingAllRefsOnDefinition.ts +++ /dev/null @@ -1,38 +0,0 @@ -/// - -//@Filename: findAllRefsOnDefinition-import.ts -////export class Test{ -//// -//// constructor(){ -//// -//// } -//// -//// public /*1*/start(){ -//// return this; -//// } -//// -//// public stop(){ -//// return this; -//// } -////} - -//@Filename: findAllRefsOnDefinition.ts -////import Second = require("findAllRefsOnDefinition-import"); -//// -////var second = new Second.Test() -////second.start(); -////second.stop(); - -goTo.file("findAllRefsOnDefinition-import.ts"); -goTo.marker("1"); - -verify.referencesCountIs(2); - -cancellation.setCancelled(); -goTo.marker("1"); -verifyOperationIsCancelled(() => verify.referencesCountIs(0) ); - -// verify that internal state is still correct -cancellation.resetCancelled(); -goTo.marker("1"); -verify.referencesCountIs(2); diff --git a/tests/cases/fourslash/syntacticClassificationsCancellation1.ts b/tests/cases/fourslash/syntacticClassificationsCancellation1.ts new file mode 100644 index 00000000000..f15ce5f9984 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsCancellation1.ts @@ -0,0 +1,21 @@ +/// + +////module M { +////} +////module N { +////} + +var c = classification; +cancellation.setCancelled(1); +verifyOperationIsCancelled(() => verify.syntacticClassificationsAre()); +cancellation.resetCancelled(); + +verify.syntacticClassificationsAre( + c.keyword("module"), + c.moduleName("M"), + c.punctuation("{"), + c.punctuation("}"), + c.keyword("module"), + c.moduleName("N"), + c.punctuation("{"), + c.punctuation("}"));